LoginSignup
12
6

JavaScriptでHTML要素取得をした際の返り値の違い(HTMLCollection, NodeList)

Last updated at Posted at 2021-07-30

:popcorn:はじめに

JavaScriptでHTMLの要素を取得する方法はいくつかあります。
jQueryでは$('セレクタ')と書いて何も考えずに取得していたのに、生のJavaScriptでは少し気を使わないといけません!
今回は取得方法による違いを見ていき、取得方法の使い分けを簡単にまとめてみたいと思います。

:popcorn:そもそもなんでHTML要素を取得したいの?

JavaScriptを使用する目的を簡潔にいうとHTML(DOM)操作をしたいからではないでしょうか?
そのためどの要素に対して(または基準として)操作をするか指定するために要素取得を行います。

JavaScript
// classを追加したり
document.getElementById('hoge').classList.add('moge');

// 子要素を追加したり
const p = document.createElement("p");
p.textContent = 'こんにちは!';
document.querySelectorAll('.moge')[0].appendChild(p);

簡単な例ですが、
このようにJavaScriptの大通りにはHTML要素取得が必要となってきます。

:popcorn:要素取得してみる

HTML要素取得の必要性がなんとなくわかったところで、HTML要素を取得する方法を何個か見ていきましょう!

こういうHTMLがあったとして

HTML
<ul id="list">
  <li class="item">アイテム</li>
  <li class="item">アイテム</li>
  <li class="item">アイテム</li>
  <li class="item">アイテム</li>
</ul>

JavaScriptでよく見るHTML取得方法を試してみる

JavaScript
document.getElementsByClassName('item');
// => HTMLCollection(4)

document.querySelectorAll('.item');
// => NodeList(4)

document.getElementById('list');
// => <ul id="list">...</ul>

取得は出来ているようですが、それぞれ返り値が違うようです(混乱)

:popcorn:返り値の違い(HTMLCollection, NodeList)

さて本題です。それぞれの返り値を見ていきましょう!

HTMLCollection

  • Element(後述)が格納されている配列風オブジェクト(Array-Like Object)
    • 取得した要素数を格納しているlengthプロパティを持っている
  • オブジェクトに[index]または.item(index)メソッドを使用してElementを取り出せる
    • 取得する要素が一個しかない場合でも配列風オブジェクトで返ってくるので[0]で取り出す
    • 要素がなければlengthが0の空の配列風オブジェクトが返ってくる
  • あくまで配列風なのでforEachは使えない
    • es6対応ブラウザならArray.from(配列風オブジェクト)で変換
    • es6未対応なら[].slice.call(配列風オブジェクト)で変換
    • 単純なforなら可能
  • 取得したElementたちを動的に保持している
    • DOMの要素数の影響を受ける
    • 要素が4つの状態で取得後、同じ要素がDOM上で5つに増えたら取得したオブジェクトの中身も5つになっている
  • 全体的にNodeListと似ている(詳しく調べられていませんが歴史的背景がありそう)

NodeList

  • Element(後述)が格納されている配列風オブジェクト(Array-Like Object)
    • 取得した要素数を格納しているlengthプロパティを持っている
  • オブジェクトに[index]または.item(indesx)メソッドを使用してElementを取り出せる
    • 取得する要素が一個しかない場合でも配列風オブジェクトで返ってくるので[0]で取り出す
    • 要素がなければlengthが0の空の配列風オブジェクトが返ってくる
    • 単純なforなら可能
  • 配列風オブジェクトだがforEachは使用できる
    • IE11はバグでNodeListにforEachは使えないので、[].slice.call(配列風オブジェクト)で変換
  • 取得したElementたちを静的に保持している
    • DOMの要素数の影響を受けない
    • 要素が4つの状態で取得後、同じ要素がDOM上で5つに増えても取得したオブジェクトの中身は4つのまま
  • 全体的にHTMLCollectionと似ている(詳しく調べられていませんが歴史的背景がありそう)

Element

  • 要素のこと(呼び方が若干違うかもれないですがこの記事ではElementと呼ぶ)
  • 上の例で言うとgetElementById('list')で取得した<ul id="list">...</ul>
    • HTMLで書かれたものが返ってくるので馴染みやすい
  • 要素がなければnull
  • 配列風オブジェクトでforEachなど使わずにHTML要素を操作したい場合は最終的にElementを指定する
    • 例) 配列風オブジェクト[0]、配列風オブジェクト.item(4)

:popcorn:結局どれの取得方法を使えばいい?

全体像

  • NodeList
    • querySelectorAll
  • HTMLCollection
    • getElements* (getElementsByClassNameとかgetElementsByTagNameとか複数とることが前提のやつ)
  • Element
    • getElementById
    • querySelector (一番はじめにヒットするものが取得できる)
    • 配列風オブジェクトをインデックス指定した時 (配列風オブジェクト[0]など)

使い分け

◇HTML上に一つしかない要素を取得したい

Elementで取れればいいのでquerySelector
→CSSやjQueryみたいにセレクタで指定できるからいいよね

◇複数要素を取得したい

扱いやすい配列で取れればいいのでquerySelectorAll
→CSSやjQueryみたいにセレクタで指定できるからいいよね
→NodeListなのでIE11でforEach使う場合は注意
→取得した値はDOMの変化に同期されないので注意。

◇要素が増減するので動的に取得したい

HTMLCollectionで取れるgetElements*

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6