HTMLCollectionとNodeListの違い【JavaScript】

HTMLCollectionとNodeListはともに配列風のオブジェクトですが、挙動が若干異なります。

今回は、HTMLCollectionとNodeListの違いについて解説していきます。

HTMLCollection

HTMLCollectionは、以下のようなメソッドで取得できる配列風のオブジェクトです。

document.getElementsByClassName()
document.getElementsByTagName()

以下のHTMLとJavaScriptで挙動を確認してみましょう。

<ul id="list">
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
</ul>

getElementsByClassNameで要素を取得してconsole.logで中身を見れば、HTMLCollectionと出力されます。

const item = document.getElementsByClassName('item'); 
console.log(item); // => HTMLCollection

NodeList

NodeListは、以下のようなメソッドで取得できる、ノードの集合です。

document.querySelectorAll()

先ほどのHTMLにあるitemクラスの要素をquerySelectorAllで取得してconsole.logで中身を見ると、NodeListと出力されます。

const item = document.querySelectorAll('.item'); 
console.log(item); // => NodeList

次に、HTML CollectionとNodeListの違いを解説していきます。

HTMLCollectionとNodeListの違い

HTMLCollectionとNodeListでは、要素の増減後の挙動とメソッドが異なります。

HTMLCollectionは動的、NodeListは静的

HTMLCollectionは後から要素の数が増減しても、動的に反映されます。

<ul id="list">
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
    <li class="item">テキスト</li>
</ul>
const item = document.getElementsByClassName('item');
console.log(item.length); // => 4

// 要素を追加
const newList = document.createElement('li');
newList.innerText = 'テキスト';
newList.classList.add('item');

const list = document.getElementById('list');
list.appendChild(newList);

console.log(item.length); // => 5

一方、NodeListは要素の数が変わっても、後からそれが反映されません。

const item = document.querySelectorAll('.item');
console.log(item.length); // => 4

// 要素を追加
const newList = document.createElement('li');
newList.innerText = 'テキスト';
newList.classList.add('item');

const list = document.getElementById('list');
list.appendChild(newList);

console.log(item.length); // => 4

DOM操作後の状態で要素を取得するには、DOM操作後に再度取得する必要があります。

メソッドが異なる

HTMLCollectionとNodeListでは使えるメソッドが異なります。

例えば、NodeListではforEachメソッドが使えますが、HTMLCollectionでは使えません。

以下はconsole.logでそれぞれ出力した結果です。

NodeListの場合

forEachメソッドが存在するのが確認できます。

ですので、以下のループ処理は問題なく動作します。

const item = document.querySelectorAll('.item');
// 動作する
item.forEach((value, index) => {
    value.classList.add('new-class');
});
HTML Collectionの場合

一方、こちらにはforEachメソッドが存在しません。

以下のコードはエラーになります。

const item = document.getElementsByClassName('item');
// エラーになる
item.forEach((value, index) => {
    value.classList.add('new-class');
});

HTMLCollectionでforEachを使ったループ処理を行いたい場合は、以下のようにします。

const item = document.getElementsByClassName('item');
Array.prototype.forEach.call( item, (value, index) => {
    value.classList.add('new-class');
});
//もしくは
[...item].forEach((value, index) => {
    value.classList.add('new-class');
});

記述が簡単なので私は[...item](スプレッド構文)を使った方法を使っています。

スプレッド構文 – JavaScript | MDN

参考リンク

それぞれの仕様や使えるメソッドなどは以下のリンクで確認してください。

HTMLCollection – Web API | MDN

NodeList – Web API | MDN

まとめ

HTMLCollectionとNodeListは似たようなオブジェクトですが、挙動が若干異なります。

違いを知っておくことで、余計なトラブルを避けましょう。

その他の記事