この魔法の仕組みと、DOM要素の検索によってアプリケーションのパフォーマンスが低下する理由を見てみましょう。
jQueryがセレクターを解析する方法
ライブラリ自体は、要素を検索するために多くの機能を備えたSizzleエンジンを使用します。 それらを検討します。
querySelectorAll()
新しいブラウザでは、ブラウザの機能を使用して要素を検索できる優れた関数querySelectorAll()およびquerySelector()が登場しました(特に、CSSを表示して要素にプロパティを割り当てるときに使用されます)。 この機能はすべてのブラウザで機能するわけではありませんが、 FF 3.1 + 、 IE8 + (IE8標準モードのみ) 、 Opera 9.5+ (?)およびSafari 3.1+でのみ機能します。 そのため、Sizzleは常にこの関数の存在を判断し、それを介して検索を実行しようとします。 ただし、ここにはいくつかの驚きがあります-querySelectorAll()を正常に使用するには、セレクタが有効でなければなりません。
簡単な例を示します。
指定された2つのセレクターは実質的に違いはなく、同じ要素のセットを返します。 ただし、最初のセレクタはquerySelectorAll()の結果を返し、2番目のセレクタは要素による通常のフィルタリングの結果を返します。
$('#my_form input[type="hidden"]')
$('#my_form input[type=hidden]')
セレクターの解析と検索
querySelectorAll()が失敗すると、Sizzleは通常のブラウザー関数getElementById()、getElementsByName()、getElementsByTagName()およびgetElementByClass()を使用しようとします。 ほとんどの場合、それらは十分にありますが、(sic!)IE <9ではgetElementByClassName()が壊れており、クラスセレクターを使用すると、このブラウザーの要素が完全に列挙されます。
一般に、Sizzleはセレクターを右から左に解析します。 この機能を説明するために、いくつかの例を示します。
$('.divs .my_class')
最初に、.my_class要素が検出され、次に親に.divを持つ要素のみがフィルターされます。 ご覧のとおり、これはかなり高価な操作であり、コンテキストを使用しても問題は解決しません(コンテキストについては後述します)。
私が言ったように-ほとんどの場合、Sizzleはセレクタを右から左に解析しますが、IDを持つ要素を使用する場合は解析しません:
$('#divs .my_class')
この場合、セレクターは期待どおりに動作し、#divs要素はコンテキストとしてすぐに使用されます。
コンテキスト
セレクターとともに$()関数に渡される2番目のパラメーターは、コンテキストと呼ばれます。 要素の検索範囲を狭めることを目的としています。 ただし、解析する場合、コンテキストはセレクターの先頭に付加されるため、まったく勝ちになりません。 コンテキストを使用することで得られる組み合わせは、querySelectorAll()の有効なセレクターです。この関数は、ドキュメントの代わりに要素だけでなく要素にも適用できるためです。 次に、コンテキストを持つセレクターは、次の構造を比fig的に変換します。
$('.divs', document.getElementById('wrapper'));
document.getElementById('wrapper').querySelectorAll('.divs'); // querySelectorAll()
この例では、querySelectorAll()を使用できない場合、Sizzleは単純な列挙で要素をフィルタリングします。
コンテキストに関するもう1つの注意(セレクターに関するものではありません)-jQueryオブジェクトを.live()関数のセレクターに渡すと、イベントはドキュメント(!)でキャッチされます。また、DOMオブジェクトが使用されると、イベントはこの要素。 私はそのような微妙な点を思い出さないようにしていますが、 .delegate()を使用しています。
フィルターとアイテム階層
ネストされた要素を検索するには、次のセレクターを使用できます。
$('.root > .child')
ご存知のように、セレクターが解析され、ページ上のすべての.child要素から検索が開始されます(querySelectorAll()が利用できない場合)。 このような操作は非常に高価であり、セレクターを次のように変換できます。
$('.child', $('.root')[0]); //
$('.root').find('.child'); // .root?
$('.root').children('.child'); //
ただし、一部の属性(:visible 、: eqなど)にフィルターを使用する必要がある場合、セレクターは次のようになります。
$('.some_images:visible')
フィルタは最後に適用されます-つまり 「右から左へ」というルールから再び出発します。
まとめ
- 可能であれば、querySelectorAll()に適した正しいセレクターを使用してください
- セレクタ内の従属をサブクエリ(.children(...)など)に置き換えます
- セレクターコンテキストを調整する
- できるだけ小さなアイテムのセットをフィルタリングする
新しい年にあなたのためのクイックセレクター! 近日中に!
イリヤ・カントールのマスタークラスと私自身の観察に基づいています。