jquery.jsを読み解く

第6回 jQueryライブラリ(1360行目~1636行目)

この記事を読むのに必要な時間:およそ 8 分

今回は,jQuery特有のセレクタ式を処理する部分になります。jQuery.filterメソッドについては次回の説明となりますが,そちらも合わせて読んで行くとより理解しやすいかと思います。

jQuery.expr

1360行目からは,セレクタ式のための正規表現を定義する部分です。

具体的な説明に入る前に,まずソースコード中に登場するm[2]とm[3]が何を表すのかを説明しておきましょう。mは1658行目にて定義されていて,jQuery.parseの正規表現にマッチした結果が格納されます。また,aには対象となる要素が格納されます。

1364行目からは,":"以降に続くフィルタの定義になります。細かな部分はjQueryドキュメントのAPI/1.2/Selectorsの部分を読んで頂ければ理解できると思うので,ここではいくつかの重要な箇所に絞って説明していきます。

1360: jQuery.extend({
1361:   expr: {
1362:     "": "m[2]=='*'||jQuery.nodeName(a,m[2])",
1363:     "#": "a.getAttribute('id')==m[2]",
1364:     ":": {
1365:       // Position Checks
1366:       lt: "i<m[3]-0",
1367:       gt: "i>m[3]-0",
1368:       nth: "m[3]-0==i",
1369:       eq: "m[3]-0==i",
1370:       first: "i==0",
1371:       last: "i==r.length-1",
1372:       even: "i%2==0",
1373:       odd: "i%2",
1374: 
1375:       // Child Checks
1376:       "first-child": "a.parentNode.getElementsByTagName('*')[0]==a",
1377:       "last-child": "jQuery.nth(a.parentNode.lastChild,1,'previousSibling')==a",
1378:       "only-child": "!jQuery.nth(a.parentNode.lastChild,2,'previousSibling')",
1379: 
1380:       // Parent Checks
1381:       parent: "a.firstChild",
1382:       empty: "!a.firstChild",
1383: 
1384:       // Text Check
1385:       contains: "(a.textContent||a.innerText||jQuery(a).text()||'').indexOf(m[3])>=0",
1386: 
1387:       // Visibility
1388:       visible: '"hidden"!=a.type&&jQuery.css(a,"display")!="none"&&jQuery.css(a,"visibility")!="hidden"',
1389:       hidden: '"hidden"==a.type||jQuery.css(a,"display")=="none"||jQuery.css(a,"visibility")=="hidden"',
1390: 
1391:       // Form attributes
1392:       enabled: "!a.disabled",
1393:       disabled: "a.disabled",
1394:       checked: "a.checked",
1395:       selected: "a.selected||jQuery.attr(a,'selected')",
1396: 
1397:       // Form elements
1398:       text: "'text'==a.type",
1399:       radio: "'radio'==a.type",
1400:       checkbox: "'checkbox'==a.type",
1401:       file: "'file'==a.type",
1402:       password: "'password'==a.type",
1403:       submit: "'submit'==a.type",
1404:       image: "'image'==a.type",
1405:       reset: "'reset'==a.type",
1406:       button: '"button"==a.type||jQuery.nodeName(a,"button")',
1407:       input: "/input|select|textarea|button/i.test(a.nodeName)",
1408: 
1409:       // :has()
1410:       has: "jQuery.find(m[3],a).length",
1411: 
1412:       // :header
1413:       header: "/h\\d/i.test(a.nodeName)",
1414: 
1415:       // :animated
1416:       animated: "jQuery.grep(jQuery.timers,function(fn){return a==fn.elem;}).length"
1417:     }
1418:   },
1419:   

1365行目に頻繁に現われるiはマッチした要素の中で何番目かを表すものです。例えば,evenを見ると2で割った余りが0だとtrueになるので,偶数番目の要素だとtrueになるという具合です。

1375行目からは親要素/子要素があるかどうか,テキストノードかどうか,可視要素かどうかを調べるためのものです。

1397行目からは,Form要素のタイプを判別するもので,対象要素のtypeがそれぞれ等しいときにtrueになります。同様にhas()はその要素がみつかればtrue,headerはh1,h2,…のヘッダ要素ならtrue,animatedはアニメーションが動作中の場合にtrueになります。

jQuery.parse(セレクタ式評価用の正規表現)

1420:   // The regular expressions that power the parsing engine
1421:   parse: [
1422:     // Match: [@value='test'], [@foo]
1423:     /^(\[) *@?([\w-]+) *([!*$^~=]*) *('?"?)(.*?)\4 *\]/,
1424: 
1425:     // Match: :contains('foo')
1426:     /^(:)([\w-]+)\("?'?(.*?(\(.*?\))?[^(]*?)"?'?\)/,
1427: 
1428:     // Match: :even, :last-chlid, #id, .class
1429:     new RegExp("^([:.#]*)(" + chars + "+)")
1430:   ],
1431: 

1420行目からは,セレクタ式をパースするための正規表現を定義している部分です。filterメソッドで利用されます。

ここでは3つの正規表現が定義されていて,コメントにあるように1423行目は [@value='test'] または [@foo] のような属性に関するものを扱う場合に利用する正規表現です。また,1426行目は :contains('foo') のように()が付いた擬似セレクタを利用する正規表現です。最後に1429行目が :even, :last-child, #id, .class のような:#.から始まる擬似セレクタとidまたはクラス指定にマッチする正規表現です。

jQuery.multiFilter()

1432:   multiFilter: function( expr, elems, not ) {
1433:     var old, cur = [];
1434: 
1435:     while ( expr && expr != old ) {
1436:       old = expr;
1437:       var f = jQuery.filter( expr, elems, not );
1438:       expr = f.t.replace(/^\s*,\s*/, "" );
1439:       cur = not ? elems = f.r : jQuery.merge( cur, f.r );
1440:     }
1441: 
1442:     return cur;
1443:   },
1444: 

1432行目からのjQuery.multiFilter()は内部的に利用するためのメソッドです。次に説明するjQuery.filterメソッドを次々に呼び出していきます。f.tには処理した式は除外されて返ってくるので,'foo, bar'のようなセレクタ式を次々に処理していくことができます。

著者プロフィール

山下英孝(やましたひでたか)

大学を卒業後,大手SIerに就職し,電機メーカーの研究所勤務を経て,ウノウに入社。1年半に渡ってWebサイトの開発,ディレクション,運用を経験した後に独立。2008年2月よりフリーエンジニアとして活動中。好きな言語はJavaScriptとPythonで,Linuxサーバ運用管理も得意。

ブログWeboo! Returns.

コメント

コメントの記入