DOMコレクション(NodeList, HTMLCollection)

DOM では、複数のノードや要素をまとめて扱うために**配列風(array-like)**のコレクション型が返されます。その代表が NodeListHTMLCollection です。両者は「配列に似ている」が「配列ではない」点が重要で、length やインデックスアクセス(collection[0])はできますが、配列の全メソッドがそのまま使えるわけではありません。


共通の特徴

  • インデックスアクセス: list[0], list.item(0)

  • 長さ取得: list.length

  • 反復処理: どちらも for...of で反復可能(ブラウザの実装が十分に新しい前提)

  • 配列ではない: 直接 map/filter/reduce は使えません(必要なら Array.from(list) かスプレッド [...] で配列に変換)


NodeList とは

任意の Node を並べたコレクションです。Element だけでなく、TextComment などが含まれる場合があります。取得元によって**静的(static)ライブ(live)**かが異なる点が最大の特徴です。

代表的な取得方法

  • element.childNodesライブNodeList(DOM変化を自動反映)

  • document.querySelectorAll(selector)静的NodeList(取得時点のスナップショット)

  • document.getElementsByName(name) … 仕様上は NodeList(実装依存でライブのことが多い)

主な性質

  • 含まれるノードの型: メソッド次第。childNodesText なども含む。querySelectorAll は要素ノードのみ。

  • 反復用メソッド: 近年の実装では NodeList.prototype.forEach が利用可能。

  • ユースケース

    • CSS セレクタで一括取得 → 静的な一覧を安全に処理したいとき(querySelectorAll

    • 子ノードを低レベルに扱う(テキストノード含む)とき(childNodes

js
// 静的 NodeList: 取得後にDOMが変わっても中身は変わらない const buttons = document.querySelectorAll('button.primary'); buttons.forEach(btn => btn.disabled = true); // ライブ NodeList: DOM変更が反映される(childNodes) const nodes = document.body.childNodes; console.log(nodes.length); // 子ノード数 document.body.append('tail'); // ここで nodes にもテキストノードが増える

HTMLCollection とは

要素(Element)のみを集めたコレクションで、常にライブです。DOM が変化すると即座に内容が更新されます。フォームや画像などの「名前付きアクセス」を備えているのが特徴です。

代表的な取得方法

  • document.getElementsByTagName('div')

  • document.getElementsByClassName('item')

  • element.children(子の要素のみ。テキストは含まない)

  • document.forms, document.images など

主な性質

  • 常にライブ: DOM の増減がそのまま反映。

  • 要素のみ: テキストやコメントは含まない。

  • 名前付きアクセス: collection.namedItem('name')collection['loginForm'](一致する id または name を持つ要素にアクセス。最初に見つかった1件)

  • 反復: for...of は可能だが、forEach はありません(配列化してから forEach を使うのが一般的)。

js
// ライブ HTMLCollection(常に最新) const items = document.getElementsByClassName('item'); console.log(items.length); // 2 とする document.body.appendChild( Object.assign(document.createElement('div'), { className: 'item' }) ); console.log(items.length); // 3 に増える(自動反映) // 名前付きアクセス(id または name 属性) const forms = document.forms; // HTMLCollection const login = forms.namedItem('login') || forms['login']; if (login) login.submit();

NodeList と HTMLCollection の違い(早見表)

観点 NodeList HTMLCollection
含まれるノード 任意の Node(取得元依存) Element のみ
ライブ/静的 取得元により両方あり(childNodes=ライブ / querySelectorAll=静的) 常にライブ
forEach 使える(近年の実装) なし(配列化して使用)
名前付きアクセス なし namedItem / collection['nameOrId']
代表的生成元 childNodes, querySelectorAll, getElementsByName getElementsBy*, children, forms, images

実践ノウハウ/ベストプラクティス

  1. 「静的で安全」か「ライブで常に最新」かを選ぶ

    • DOM を変更しながら反復する処理では、ライブコレクションはバグの温床になりがちです。意図せず要素の増減でインデックスがずれ、取りこぼしや重複処理が起きます。
      → 変更しながら反復する場合は、最初に配列へコピーすると安全です。

    js
    const list = document.getElementsByClassName('row'); // HTMLCollection(ライブ) [...list].forEach(el => el.remove()); // 配列にしてから安全に反復
  2. 配列メソッドを使いたいなら配列化する

    js
    const nodes = document.querySelectorAll('li'); // NodeList(静的) const arr = Array.from(nodes); // または [...nodes] const titles = arr.map(li => li.textContent.trim());
  3. 子ノードの種類に注意

    • childNodes(NodeList)はテキストやコメントも含む。

    • children(HTMLCollection)は要素のみ。
      要素だけ欲しいなら children または querySelectorAll を使うと意図通りになります。

  4. パフォーマンス配慮

    • ライブコレクションは参照するたびに最新状態を計算するコストが発生し得ます。サイズを何度も使うなら一度ローカル変数へ保存する、必要に応じて配列化する、querySelectorAll の静的結果を用いるなどが有効です。

  5. イベント付与の設計

    • ライブに増える要素へ都度リスナーを付けるより、親要素に一括でハンドラを置くイベントデリゲーションの方が堅牢なことが多いです。

    js
    const list = document.querySelector('#todo'); list.addEventListener('click', (e) => { const item = e.target.closest('li'); if (item) item.classList.toggle('done'); });

典型パターン集

1) CSS セレクタで一括取得(静的)

js
const links = document.querySelectorAll('nav a'); // NodeList(静的) for (const a of links) a.setAttribute('rel', 'noopener');

2) 名前付きフォームへのアクセス(ライブ)

js
// <form id="login" name="login"> ... </form> const loginForm = document.forms.namedItem('login'); // HTMLCollectionから取得 loginForm?.reset();

3) 要素だけの子一覧がほしい

js
const children = document.getElementById('box').children; // HTMLCollection(要素のみ) [...children].forEach(el => el.classList.add('in-box'));

4) NodeList を配列にして配列メソッドを使う

js
const items = Array.from(document.querySelectorAll('.item')); const visibleIds = items .filter(el => el.offsetParent !== null) .map(el => el.id);

まとめ

  • NodeList は取得元によって静的/ライブが異なり、要素以外のノードを含むことがある汎用コレクション。querySelectorAll は静的な NodeList を返すため、スナップショット処理に向く

  • HTMLCollection は常にライブで要素のみ。getElementsBy* 系や childrenforms などが返し、名前付きアクセスが可能。

  • 配列操作や DOM 変更を伴う反復では、配列化(Array.from / スプレッド)イベントデリゲーションを取り入れると安全で効率的です。

ChatGPT5 生成日:2025/09/11