jquery.jsを読み解く
第7回 jQueryライブラリ(1637行目~1794行目)
ここ最近,JavaScript開発者の間で「jQuery」はかなりの盛り上がりを見せていますが,ついにGoogle検索キーワードの人気でも「prototype.js」を上回ったようです。まだ使ったことがないという方も,ぜひこの機会に触れてみてはいかがでしょうか。まず試しに使ってみる→内部がどうなっているか気になる→jQueryのソースを読む,というプロセスを経ることでよりjQueryへの理解が深まるのではないかと思います。
さて,今回はjQuery.filterなどの内部処理用メソッドを説明していきます。
jQuery.classFilter()
1637: classFilter: function(r,m,not){
1638: m = " " + m + " ";
1639: var tmp = [];
1640: for ( var i = 0; r[i]; i++ ) {
1641: var pass = (" " + r[i].className + " ").indexOf( m ) >= 0;
1642: if ( !not && pass || not && !pass )
1643: tmp.push( r[i] );
1644: }
1645: return tmp;
1646: },
1647:
jQuery.classFilterメソッドは,引数 r の要素から引数 m というクラス名が指定されている要素のみを抽出するメソッドです。1638行目および1641行目で,クラス名の前後に空白を付与してデリミタとして利用しています。また,1642行目のif文により,第3引数 not がtrueの場合は逆の動作になり,クラス m が指定されていない要素のみが返されます。
jQuery.filter()
jQuery.filterメソッドは,find(),filter()などから利用される内部処理用のメソッドです。長いのでいくつかに区切って見ていきましょう。
1648: filter: function(t,r,not) {
1649: var last;
1650:
1651: // Look for common filter expressions
1652: while ( t && t != last ) {
1653: last = t;
1654:
1655: var p = jQuery.parse, m;
1656:
1657: for ( var i = 0; p[i]; i++ ) {
1658: m = p[i].exec( t );
1659:
1660: if ( m ) {
1661: // Remove what we just matched
1662: t = t.substring( m[0].length );
1663:
1664: m[2] = m[2].replace(/\\/g, "");
1665: break;
1666: }
1667: }
1668:
1669: if ( !m )
1670: break;
1671:
1648行目から見ていきましょう。第1引数 t にセレクタ式,第2引数 r に要素配列が渡されてきます。第3引数 not はフィルタ条件を反対にするboolean値です。
1653行目でlastの値として,セレクタ式 t を設定しています。このセレクタ式内の文字列に対して繰り返し処理を行っていきます。順に処理を行いlastの値が変化していくため,lastの値が変化していなかったら終了となります。
1655行目のjQuery.parseは1421行目で定義されているセレクタ式評価用の正規表現になります。1657行目のfor文は,そのjQuery.parseの結果でマッチするものがあれば変数 m に格納して,マッチした文字列を除いたものをtに格納します。これ以降は,このマッチした文字列に対し処理を行っていきますので,マッチする文字列がなければ,1670行目にてwhileループを抜けます。
1672: // :not() is a special case that can be optimized by
1673: // keeping it out of the expression list
1674: if ( m[1] == ":" && m[2] == "not" )
1675: // optimize if only one selector found (most common case)
1676: r = isSimple.test( m[3] ) ?
1677: jQuery.filter(m[3], r, true).r :
1678: jQuery( r ).not( m[3] );
1679:
1680: // We can get a big speed boost by filtering by class here
1681: else if ( m[1] == "." )
1682: r = jQuery.classFilter(r, m[2], not);
1683:
1684: else if ( m[1] == "[" ) {
1685: var tmp = [], type = m[3];
1686:
1687: for ( var i = 0, rl = r.length; i < rl; i++ ) {
1688: var a = r[i], z = a[ jQuery.props[m[2]] || m[2] ];
1689:
1690: if ( z == null || /href|src|selected/.test(m[2]) )
1691: z = jQuery.attr(a,m[2]) || '';
1692:
1693: if ( (type == "" && !!z ||
1694: type == "=" && z == m[5] ||
1695: type == "!=" && z != m[5] ||
1696: type == "^=" && z && !z.indexOf(m[5]) ||
1697: type == "$=" && z.substr(z.length - m[5].length) == m[5] ||
1698: (type == "*=" || type == "~=") && z.indexOf(m[5]) >= 0) ^ not )
1699: tmp.push( a );
1700: }
1701:
1702: r = tmp;
1703:
1674行目は,セレクタ式に「:not(selector)」の書式が含まれていた場合の処理で,第3引数notをtrueにして,自身のjQuery.filterメソッドを呼び出し直します。ただし,1676行目の三項式によりfoo#barのように「:」「#」「[」「.」を間に含む場合はnot()メソッドを利用します。
1681行目は,セレクタ式が「.foo」のようなクラス指定の場合の処理で,この場合はjQuery.classFilterメソッドを利用します。
1684行目は,[attribute=value]のような属性フィルタ式の場合の処理になります。1688行目で変数aに検索対象の要素を設定し,jQuery.propsまたは属性プロパティを直接参照して結果を変数zに格納します。値が見つからないか,attributeの値が href, src, selected の場合は,次にjQuery.attrメソッドを用いて値を取得します。そして1693行目ですが,関係演算子が 「=」「!=」「^=」「$=」「$=」「*=」「~=」の場合の処理を1つのif文だけで処理しています。論理演算子||や&&をうまく活用して,tこの条件に合致したものを配列に格納します。
jquery.jsを読み解く
- 第13回 jQueryライブラリ(2834行目~3107行目)
- 第12回 jQueryライブラリ(2530行目~2833行目)
- 第11回 jQueryライブラリ(2365行目~2529行目)
- 第10回 jQueryライブラリ(2183行目~2364行目)
- 第9回 jQueryライブラリ (1962行目~2182行目)
- 第8回 jQueryライブラリ(1795行目~1961行目)
- 第7回 jQueryライブラリ(1637行目~1794行目)
- 第6回 jQueryライブラリ(1360行目~1636行目)
- 第5回 jQueryライブラリ (1094行目~1359行目)
- 第4回 jQueryライブラリ(770行目~1093行目)


