jQueryの強力な機能のひとつに、 $('#the-target')
のようにCSSのセレクターを用いて要素検索できるというものがあります。この要素検索を行うモジュールにはSizzleという名前が付けられています。
一方、近代的なブラウザーには .querySelectorAll()
がネイティブで実装されています。こちらもCSSのセレクターで要素検索できるメソッドです。
var $elems = $('elem#id.class, .and.more.selectors'); var elems = document.querySelectorAll('elem#id.class, .and.more.selectors');
JavaScriptで何かするよりも、ネイティブでやった方が高速です。じゃあSizzleなんていらないんじゃないの?と思われるかもしれません。実際、jQuery互換軽量フレームワークを詠うZepto.jsでは、ほとんどそのまま querySelectorAll()
を利用しています。(そのために古いIEでは正常に動作しませんが。)
それでもjQueryはSizzleを使い続ける方針です。Sizzleが .querySelectorAll()
に勝る点とは、何でしょうか。
参考
クロスブラウザーとバグ対策
まずはこれです。IE 6, 7では .querySelectorAll()
が実装されていないので、その場合はもちろんSizzleのようなエンジンが必要になります。
しかしIEに限らず、他のブラウザーもちょっとずつ不具合を抱えている——とjQueryチームは主張しています。Sizzleはそれを吸収する役割を担っているわけです。
昔は .querySelectorAll()
はなかった
jQueryが公開された当初は .querySelectorAll()
はまだ実装されていませんでした。
Selectors API が使えるブラウザ
2008 年 3 月 6 日現在の一覧
- WebKit Nightly Builds (開発版の Safari)
- Internet Explorer – Web Browser for Microsoft Windows (IE8 の Beta 版)
最初のjQuery 1.0が公開されたのは2006年8月26日です。
- August 26th, 2006
- First stable version of jQuery: jQuery 1.0
なお .querySelectorAll()
の実装は先になりましたが、仕様 (Selectors API) 自体は2006年に既に公開されています。
W3C Working Draft 25 May 2006
またjQuery自体も、他のCSSセレクターで要素を検索するJavaScriptライブラリーを参考にしていたようです。
セレクターの拡張
基本的にはW3Cのセレクターの仕様に則っているのですが、敢えて独自仕様に変え、使いやすくしているものもあります。
拡張 :not()
例えば否定疑似クラス :not()
は、本来CSSでは単純セレクター (simple selector) を与える事しかできません。Sizzleはこれを拡張し、複合セレクター (complex selector) を利用できるようにしています。
".aaa:not(.xxx)" // jQuery ... OK, querySelectorAll() ... OK ".aaa:not(.xxx.yyy)" // jQuery ... OK, querySelectorAll() ... NG
独自セレクター
:first
あたりがよく利用されるかなと思うのですが、これはjQueryが独自に制定したセレクターです。(CSSにも :first-child
がありますが、別の機能です。) もっとも.querySelectorAll()
の方は単純に [0]
と取れば済む話ですが……。
jQueryが拡張しているセレクターの一覧はこちら。
- [jQuery Extensions – jQuery API)[http://api.jquery.com/category/selectors/jquery-selector-extensions/)
幾つか例を挙げます。
:odd
, :even
偶数番目、奇数番目のものだけを抽出します。
[attr!=value]
属性の値が指定のものでない要素を抽出します。属性セレクターは =
のあたりが何パターンかありますが、 !=
はCSS2, CSS3では存在しません。
任意の拡張
カスタムセレクターを独自に定義する事ができます。
この例だと :unkomorimori
という疑似クラスを定義しています。ウンコー ヽ(・∀・)ノ●
Sizzleを削るとどれくらい軽くなるか
試しに削って圧縮してみました。
状態 | ファイルサイズ | 比率 |
---|---|---|
元の jquery-1.8.1.js |
218,346 | 100% |
そのまま圧縮 | 93,039 | 43% |
Sizzleを削って圧縮 | 77,678 | 36% |
15KB軽くなりましたね。大きいような、小さいような。
実際はSizzleの機能に依存している部分があるはず(未確認)ですし、 .querySelectorAll()
に置き換えてすらいないで、この通りにはいきません。
圧縮にはUglifyJSを使っています。削ったのはSizzleのコメントが付けられた匿名関数全体です。
Sizzleは遅いか
もちろん .querySelectorAll()
と比べると遅いはずですが、そこはあまり気にする必要はないと思います。0.1msと0.01msは10倍の差ですが、体感に差は全くないでしょう?
有為な差が出る程に要素検索を多用しているのなら、それは既に設計の問題です。適宜DOMオブジェクトへの参照をキャッシュしておくべきです。また検索も複雑なセレクターではなくID、せめてクラスを使えば高速化できるでしょう。
で、Sizzleは必要か?
ここまでSizzleの独自機能を挙げてきましたが、それでも .querySelectorAll()
が使えるなら、Sizzleはなくても良いんじゃないかなーと正直思ってます……。
ええと、書いてて飽きたのでここまでにします。コメント欄にツッコミお願いしますね。
とっぴんぱらりのぷう。