要素の取得
要素オブジェクトの参照を取得する方法として、getElementByIdやquerySelectorというDOM APIがあります。
この2つのAPIはどちらもidを指定して要素を取得できますが、目的の要素の探索方法が異なります。
idというのはドキュメント内で一意である必要があります。
querySelectorはidの他にも様々な方法で取得する要素の条件を指定できるため、idのみの指定を受け付けるgetElementByIdとは探索アルゴリズムが異なっているわけですね。
querySelector
querySelector()はCSS セレクタの記法を用いて要素を取得する関数です。
ドキュメント内の要素でセレクタに一致する最初のものを返します。
documentオブジェクトのほか、要素オブジェクトにも存在するAPIで、要素オブジェクトにあるquerySelectorはその要素内のみを探索します。
idを指定するときには、querySelector(#foo)のように#を使って指定します。
getElementByIdの場合には#の指定は不要ですが、querySelectorでは#をつけないとidではなくタグ名で探索されてしまいます。
探索方法
querySelector()はドキュメント内を上から順に探索していきます。
上から順に1つずつ探索し、セレクタに一致した要素が返されます。
これは線形探索であり、計算量はO(N) となります。
getElementById
getElementById()は引数に渡したidをもつ要素オブジェクトを取得する関数です。
documentオブジェクトから生えているAPIであり、要素オブジェクトには生えていない点がquerySelectorとは異なっています。
idが一意に設定されていなかった場合には、指定したidをもつドキュメント内の最初の要素が返されます。
また、指定したidをもつ要素が見つからなかった場合にはnullが返されます。
探索方法
getElementById()によって要素を探索するとき、(ブラウザの実装によりますが、)ハッシュマップのようなデータ構造を使用して探索を行う場合、計算量はO(1)となります。
idと対応する要素を紐づけているため、高速に取得することができるわけです。
getElementByIdはquerySelectorと比べて高速です。
計測
10万個ほどの要素をもつドキュメント内の初めの方にある要素と終わりの方にある要素を取得するのにかかる時間を以下のようなhtmlで計測してみます(計測は1度のみ行っています)。
<html>
<body>
<div id="first">first target</div>
{... 約10万個の<div>要素}
<div id="target">last target</div>
</body>
<script>
console.time('querySelector')
const target = document.querySelector('#target')
console.timeEnd('querySelector')
console.time('getElementById')
const targetElementById = document.getElementById('#target')
console.timeEnd('getElementById')
console.time('querySelectorFirst')
const targetFirst = document.querySelector('#first')
console.timeEnd('querySelectorFirst')
console.time('getElementByIdFirst')
const targetElementByIdFirst = document.getElementById('#first')
console.timeEnd('getElementByIdFirst')
</script>
</html>
ドキュメントの初めの方にある要素<div id="first">first target</div>を取得するまでにかかった時間は以下の通りです。
querySelectorFirst: 0.001953125 ms
getElementByIdFirst: 0.0009765625 ms
ドキュメントの初めの方にある要素を取得する場合には、querySelector()はgetElementById()の約2倍の時間がかかっています。
一方、ドキュメントの最後の方にある要素<div id="target">last target</div> を取得するまでにかかった時間は以下の通りです。
querySelector: 0.069091796875 ms
getElementById: 0.003173828125 ms
10万個の要素を上から探索しているquerySelector()は、getElementById()の20倍以上の時間がかかってしまっています。
要素数が大きいほど、両者の処理時間の差が開いていくことが確認できます。
計測環境
以下の環境で計測を行っています。
OS macOS バージョン15.1.1
Google Chrome 131.0.6778.109 (Official Build) (arm64)
JavaScript V8 13.1.201.15
さいごに
document.querySelector()とdocument.getElementById()とでは、getElementById()の方が高速に処理できます。
idを指定して要素を取得する際には、パフォーマンスの観点ではgetElementById()に軍配が上がります。