DOM操作の要素取得メソッドが多くて、どれを使えば良いのかわからない
この声にお答えします。
DOM操作するためのメソッドは何個もあります。
そのため同じ要素を取得できるメソッドが複数あり、どれを使えば良いかわからない時はありませんか。
本記事ではどういうDOM操作のメソッドがあって、それぞれをどう使えば良いのか見ていきます。
対象読者
- どの場面でどの要素取得メソッドを使用すべきか知りたい人
querySelectorAll
とgetElements*
の違いを知りたい人- 要素取得後に
for
とforEach
のどちらを使えるか知らない人
それでは早速やっていきましょう
要素の取得方法のベストプラクティス
どの場面でどのメソッドを使用すべきか見ていきます。
本記事で取り上げるメソッドは以下です。
getElementById()
- idが指定した文字列に一致する要素を取得する
getElementsByClassName()
- 指定したクラス名を全て持つ要素を全て取得する
getElementsByTagName()
- タグ名が指定した文字列に一致する要素を全て取得する
getElementsByName()
- nameが指定した文字列に一致する要素を全て取得する
querySelector()
- 指定したCSSセレクタに該当する要素を取得する
querySelectorAll()
- 指定したCSSセレクタに該当する要素を全て取得する
実行にかかる時間の順番を早い順に並べると、
getElemensBy
≒ getElemensBy*
<
querySelector
<
querySelectorAll
となるみたいです。(実行速度は公式ドキュメントに記載されているわけではなく、他サイトから拾ってきた情報をもとに推測しています)
なので、実行速度面で考えるベストプラクティスは以下になりそうです。
- まず
id
で要素を指定できるならgetElementById
を使い、 -
id
で指定できない場合
タグで指定できるならgetElementsByTagName
クラスで指定できるならgetElementsByClassName
name
属性で指定できるならgetElementsByName
を使う - 上記のいずれでも指定できない要素を取得したい時は
querySelector
、querySelectorAll
を使う
ただ実行速度はメソッドを1000回実行してもms程度です。
なので、よほどDOM操作を多用していたり、大規模なHTMLでなければ、実行速度の違いは感じづらいと思います。
個人的には、getElementById
で要素を取得できるか考えて、取得できなければ思考停止で querySelector
、 querySelectorAll
を使い回していこうと思っています。
実践:要素の取得
状況別に要素の取得で使用できるメソッドをまとめました。
以下のHTMLを仮定します。
<h2 class="itemsList">商品一覧</h2>
<section id="newItems">
<h3>新商品</h3>
<p class="item new">新商品A</p>
<p class="item new">新商品B</p>
</section>
<section id="saleItem">
<h3>セール中の商品</h3>
<p class="item sale">セール商品A</p>
</section>
<section id="popularItem">
<h3>人気商品</h3>
<p class="item popular">人気商品A</p>
</section>
<div>
<button type="button" name="buy"value="100">購入ボタン</button>
<button type="button" name="cancel"value="0">キャンセル</button>
</div>
<form>
<legend>連絡方法</legend>
<fieldset>
<div>
<label for="option1">メール</label>
<input type="radio" id="option1" name="contact" value="email">
<label for="option2">電話</label>
<input type="radio" id="option2"name="contact"value="phone">
</div>
<div>
<button type="submit">送信</button>
</div>
</fieldset>
</form>
取得する要素が一つの時
idで要素を指定できる時は getElementById
を使う
document.getElementById("newItems");
CSSセレクタでしか要素を指定できない時は、queySelector
を使う
document.querySelector("#newItems .item:last-child")
タグ名で取得できる時は querySelector
か getElementsByTagName
を使う
document.querySelector("h2")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByTagName("h2")
クラス名で取得できる時は querySelector
か getElementsByClassName
を使う
document.querySelector(".itemsList")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByClassName("itemsList")
name
で取得できる時は querySelector
か getElementsByName
を使う。
document.querySelector("[name='buy']")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByName("buy")
取得する要素が複数の時
クラス名で複数の要素を取得する時は querySelectorAll
か getElementsByClassName
を使う
document.querySelectorAll(".item.new")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByClassName("item new")
タグ名で複数の要素を取得する時は querySelectorAll
か getElementsByTagName
を使う
document.querySelectorAll("h3")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByTagName("h3")
name
で複数の要素を取得する時は querySelectorAll
か
getElementsByName
を使う
document.querySelectorAll("[name='contact']")
// 実行速度で言うと以下の方が早いと思われる
document.getElementsByName("contact")
実践:複数の要素を取得後の、各要素へのアクセス方法
querySelectorAll
や getElementsBy*
メソッドでは複数の要素を取得できます。その後の各要素へのアクセス方法についての解説です。
特定の要素にアクセスする
要素取得のメソッドがquerySelectorAll
の時も、getElementsBy*
の時も同じ方法で特定の要素にアクセスできます。
const newItems = document.querySelectorAll(".item.new")
// 以下いずれかの方法で特定の要素にアクセスできる。
newItems.item(0);
newItems[0];
const newItems = document.getElementsByClassName("item new");
// 以下いずれかの方法で特定の要素にアクセスできる。
newItems.item(0);
newItems[0];
取得した要素全てにアクセスする
取得した要素全てにアクセスしたい場合は、ループ処理を行います。
取得時に使用したメソッドによって処理の方法は変わってきます。
(これは HTMLCollection
と NodeList
の違いによるところです。後述の補足で解説します)
querySelectorAll
か getElementsByName
で取得した要素は forEach
でループ処理を行えます。
// querySelectorAll
const newItems = document.querySelectorAll(".item.new")
newItems.forEach(newItem => {
console.log(newItem);
})
// getElementsByName
const contact = document.getElementsByName("contact")
contact.forEach(item => {
console.log(item)
})
getElementsByClassName
と getElementsByTagName
の時は forEach
は使えません。
代わりに for...of
か for
を使います。
// getElementsByClassName
const newItems = document.getElementsByClassName("item new");
for(const newItem of newItems){
console.log(newItem);
}
for(let i=0; i < newItems.length; i++){
console.log(newItems[i]);
}
// getElementsByTagName
const heading3s = document.getElementsByTagName("h3")
for (const heading3 of heading3s) {
console.log(heading3);
}
for(let i=0; i < heading3s.length; i++){
console.log(heading3s[i]);
}
補足:HTMLCollection と NodeListの違いについて
HTMLCollection
と NodeList
は配列風のオブジェクトです。
配列風であって配列ではないのがポイントです。
HTMLCollection もしくは NodeList が取得されるメソッド
要素取得時に使用するメソッドによって、HTMLCollection
が取得される場合と NodeList
が取得される場合があります。
HTMLCollection
は以下のようなメソッドで取得されます。
getElementsByClassName
getElementsByTagName
NodeList
は以下のようなメソッドで取得されます。
querySelectorAll
getElementsByName
では基本的に NodeList
が取得されますが、IEやEdgeでは HTMLCollection
が取得されるようです。
特徴の違い
具体的な HTMLCollection
と NodeList
の違いについてですが、以下になります。
- 要素が増減した時の違い
HTMLCollection
は要素数の変更が反映されます。
これはライブオブジェクトと呼ばれる性質のオブジェクトだからです。NodeList
は基本的には要素数が変更しても反映されません。(ただし中にはNodeList
でもライブオブジェクトの性質を持つものもあります。例えば、childNodes
プロパティの返り値などです。) - 使用できるメソッドの違い
HTMLCollection
よりもNodeList
の方が使えるメソッドが比較的多いです。
例えば、forEach
メソッドはNodeList
にはありますがHTMLCollection
にはありません。
逆に、HTMLCollection
では使えるがNodeList
では使えないメソッドもあるが、少ない(namedItem
メソッド)。
まとめ
querySelector
と querySelectorAll
で大体の要素取得がまかえます。
getElementsBy*
を使う理由は実行速度が早い、要素数の変更が動的に反映されるといったところでしょうか。
本記事の筆者は、getElementsBy*
の恩恵をまだ肌で感じたことはないので、とりあえず querySelector
を使っていこうと思います。
コメント