かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

JavaScript NodeList, HTMLCollection は配列(Array)ではない

テーブルのtr内の th, td を丸っと処理したいみたいなケースを考えると、querySelectorAll('tr') で tr を取得してループで回し、それぞれの tr で tr.childNodestr.children すれば th, td が取得できそうなイメージになります。
しかしquerySelectorAllElement.childNodesElement.children などで取得される NodeList, HTMLCollection.length で要素数を取得したりはできるのですが、配列ではないので map とか some のような配列のメソッドが使えない場合があります。

NodeList は forEach でループ処理することができる

querySelectorAll, Element.childNodes で取得されるのは NodeList
NodeListforEach を使うことができる。

const table = document.getElementById('#table');
table.querySelectorAll('tr').forEach((row) => {
  row.childNode.forEach((cell) => {
    // <th>, <td> の処理
  });
});

forEach 以外の反復処理させるメソッドを使おうとするとエラーになる

table.querySelectorAll('tr').map((row) => {...});
// => Uncaught TypeError: table.querySelectorAll(...).map is not a function

row.childNode.some((cell) => {...});
// => Uncaught TypeError: row.childNodes.some is not a function

HTMLCollection は forEach も使えない

getElementsByClassNameElement.children で取得されるのは HTMLCollection
HTMLCollectionforEach も使えない。

const table = document.getElementById('#table');
table.getElementByClassName('row').forEach((row) => { ... });
// => Uncaught TypeError: table.getElementsByClassName(...).forEach is not a function

NodeList, HTMLCollection で map などの反復処理メソッドを使いたい場合

Array.from や スプレッド構文で配列に変換すればOK

const table = document.getElementById('#table');
// Array.from で配列に変換
Array.from( table.querySelectorAll('tr') ).map((row) => { ... });
// [...] で配列に変換
[...table.children].filter((child) => { ... }); 

NodeList と HTMLCollection の違い

NodeListHTMLCollection も参照している要素への変更は反映されるが、保持している要素数の増減に違いがある。

  • NodeList は取得した時点の要素を保持する (静的)
  • HTMLCollection は要素数に変化があれば増減後の要素になる (動的・参照みたいな感じ)
<ul id="list">
  <li>list-1</li>
  <li>list-2</li>
</ul>
const list = document.getElementById('list');
const nodeList = list.querySelectorAll('li'); // NodeList
const collection = list.children; // HTMLCollection

nodeList.length;   // => 2
collection.length; // => 2

// 参照しているDOM要素の変更
nodeList[0].textContent += ' edited by NodeList';
collection[1].textContent += ' edited by HTMLCollection';

nodeList[1].textContent;
// => list-2 edited by HTMLCollection
collection[0].textContent;
// => list-1 edited by NodeList

// 要素数の変化
const li = document.createElement('li');
li.textContent = 'list-3';
list.appendChild(li);

nodeList.length;   // => 2
collection.length; // => 3
Sample

See the Pen nodeList vs HTMLCollection by KIKIKI (@chaika-design) on CodePen.

 
最近お仕事で全くコード書く機会がないから忘れる。


[参考]

リスト:超絶技巧練習曲集

リスト:超絶技巧練習曲集