“querySelector” – Alphabetical Advent Calendar 2013
この記事は賞味期限切れです。(更新から1年が経過しています)
“Q” は querySelector の “Q”。
querySelector / querySelectorAll
querySelector / querySelectorAll は、”#container .section” のようなCSSのセレクタで要素を絞り込んで取得する為のAPIです。 旧来jQuery等で使われていた要素の取得がネイティブのAPIとして実装されたと考えれば、特に難しいことはないですね。 IEは8以降でこの機能をサポートしていますが、IE8ではCSS2のセレクタのみ使用可能となっています。
querySelector[All] は document から呼び出して使用します。
document.querySelector("#container .section");
document.querySelectorAll("#container .section");
両者の違いは取得する要素の数です。 querySelector は条件に合致した最初の要素だけを返し、 querySelectorAll は合致した全ての物を返します。
<div id="container">
<div class="section section-01"></div>
<div class="section section-02"></div>
<div class="section section-03"></div>
</div>
<script>
var firstSection = document.querySelector("#container .section"); // HTMLDivElement
var allSections = document.querySelectorAll("#container .section"); // NodeList
</script>
querySelectorAll で返される NodeList は Arrayライクなオブジェクトで、 配列のように添字で取得できるほか、インデックスで要素を返す item() メソッドが使用できます。
// これらは同じ要素を返します
allSections[0];
allSections.item(0);
他の要素取得系APIと比べて
要素の取得と言えば、getElementById / getElementsByClassName / getElementsByTagName がありますが、 想像に難くないようにこれらの方が高速な為、場面による使い分けが大切です。
使い分けが面倒、あるいは毎度 document… と書くのが鬱陶しい場合は、 セレクタから判別して処理する関数を書いてみても良いかもしれません。
var _query = function(selector){
var nodes;
if(/^#[\w\-]+$/.test(selector)){
return [document.getElementById(
selector.replace(/^#/, "")
)];
}
if(/^\.[\w\-]+$/.test(selector)){
nodes = document.getElementsByClassName(
selector.replace(/^\./, "")
);
} else if((/^[a-z]+$/i).test(selector)) {
nodes = document.getElementsByTagName(selector);
} else {
try {
nodes = document.querySelectorAll(selector);
} catch(e){
nodes = [];
}
}
return [].slice.call(nodes);
};
_query("#container"); // Array
_query(".section"); // Array
_query("div"); // Array
_query("#container .section"); // Array
ここで使われる id や class の文字については半角英数字とハイフン/アンダースコアのみに絞っています。 ついでに、forEach などが使えるように NodeList から配列に変換しています。
ただ、この場合は正規表現などのコストで有り難みが半減するかもしれません。
jQuery(Sizzle)と比べて
jQueryの独自のセレクタは要素を1つずつ検証していく為、やはりネイティブの querySelector に比べて速度が落ちてしまいます。 そのためjQueryは、
- id や class やタグ名を渡された場合はそれに相応しいネイティブAPIを使用し、
- ブラウザが querySelector が対応しているかどうかをチェックし、
- querySelector で正常に解釈できるセレクタであるかどうかのテストを行い、
- 失敗した場合(例えばjQuery独自の記法が使用されていた場合)に自分のAPIを使用して要素を抽出する
こんな感じのプロセスを踏んでいる様です。
つまりjQueryを使用する場合でも、まずは id や class で絞込み、 それに対して .find() などでフィルタリングする事で速度が改善しそうですね。
こちらで詳しく説明されています。
コメント