この回答のために、私はを参照querySelector
してquerySelectorAll
ようquerySelector *とにgetElementById
、getElementsByClassName
、getElementsByTagName
、およびgetElementsByName
getElementとして*。
主な違い
- querySelector *は、ID、タグ、またはクラスの単純なセレクターだけでなく、任意のCSS3セレクターを渡すことができるため、より柔軟です。
- querySelectorのパフォーマンスは、呼び出されるDOMのサイズによって変化します。*正確には、querySelector *呼び出しはO(n)時間で実行され、getElement *呼び出しはO(1)時間で実行されます。nは、呼び出された要素またはドキュメントのすべての子の総数です。この事実はあまり知られていないようですので、私はそれを大胆に述べています。
- getElement *呼び出しはDOMへの直接参照を返しますが、querySelector *は内部的に選択された要素のコピーを作成してから参照を返します。これらは「ライブ」および「静的」要素と呼ばれます。これは、返される型に厳密には関連していません。要素がある時点でコピーされたかどうかに依存し、データの固有のプロパティではないため、プログラムで要素がライブであるか静的であるかを知る方法はありません。ライブ要素への変更はすぐに適用されます-ライブ要素を変更するとDOMで直接変更されるため、JSの次の行でその変更を確認でき、その要素を参照する他のライブ要素にすぐに伝達されます。静的要素への変更は、現在のスクリプトの実行が完了した後にのみ、DOMに書き戻されます。
- これらの呼び出しの戻りタイプは異なります。
querySelector
そして、getElementById
の両方が単一の要素を返します。querySelectorAll
また、getElementsByName
どちらもNodeListを返します。これは、HTMLCollectionが古くなってから追加された新しい関数です。古いものgetElementsByClassName
とgetElementsByTagName
両方がHTMLCollectionsを返します。繰り返しますが、これは要素がライブであるか静的であるかには本質的に無関係です。
これらの概念を次の表にまとめます。
Function | Live? | Type | Time Complexity
querySelector | N | Element | O(n)
querySelectorAll | N | NodeList | O(n)
getElementById | Y | Element | O(1)
getElementsByClassName | Y | HTMLCollection | O(1)
getElementsByTagName | Y | HTMLCollection | O(1)
getElementsByName | Y | NodeList | O(1)
詳細、ヒント、例
HTMLCollectionsは、NodeListsほど配列のようなものではなく、.forEach()をサポートしていません。これを回避するには、spreadオペレーターが便利です。
[...document.getElementsByClassName("someClass")].forEach()
すべての要素、およびグローバルはdocument
、これら以外のすべての機能にアクセスする必要がありgetElementById
とgetElementsByName
のみに実装されています、document
。
querySelector *を使用する代わりにgetElement *呼び出しをチェーンすると、特に非常に大きなDOMでパフォーマンスが向上します。小さなDOMや非常に長いチェーンでも、一般的には高速です。ただし、パフォーマンスが必要であることがわかっている場合を除き、querySelector *の読みやすさを優先する必要があります。querySelectorAll
すべてのステップでNodeListまたはHTMLCollectionから要素を選択する必要があるため、多くの場合、書き換えが困難です。たとえば、次のコードは機能しません。
document.getElementsByClassName("someClass").getElementsByTagName("div")
because you can only use getElements* on single elements, not collections. For example:
`document.querySelector("#someId .someClass div")`
could be written as:
document.getElementById("someId").getElementsByClassName("someClass")[0].getElementsByTagName("div")[0]
Note the use of `[0]` to get just the first element of the collection at each step that returns a collection, resulting in one element at the end just like with `querySelector`.
すべての要素がquerySelector *とgetElement *の両方の呼び出しにアクセスできるため、両方の呼び出しを使用してチェーンを作成できます。これは、パフォーマンスを向上させたい場合に役立ちますが、getElement *呼び出しに関して記述できないquerySelectorを回避することはできません。
一般に、セレクターをgetElement *呼び出しのみを使用して作成できるかどうかを判断するのは簡単ですが、明らかでない場合があります。
document.querySelectorAll(".class1.class2")
次のように書き換えることができます
document.getElementsByClassName("class1 class2")
querySelector *でフェッチされた静的要素に対してgetElement *を使用すると、querySelectorによってコピーされたDOMの静的サブセットに関しては有効ですが、完全なドキュメントDOMに関しては有効ではない要素になります...これが簡単な場所です要素のライブ/静的解釈はバラバラになり始めます。これについて心配する必要がある状況はおそらく避ける必要がありますが、そうする場合は、querySelector *が参照を返す前にそれらが見つけた要素をコピーしますが、getElement *呼び出しはコピーせずに直接参照をフェッチします。
複数の一致がある場合、どちらのAPIも最初に選択する要素を指定しません。
querySelector *は、一致が見つかるまでDOMを反復処理するため(主な相違点#2を参照)、上記のことは、DOMで探している要素の位置に依存して、迅速に見つかることを保証できないことを意味します。ブラウザは、DOMを逆方向、順方向、深さ優先、幅優先などで反復できます。getElement *は、配置に関係なく、ほぼ同じ時間で要素を検索します。