JavaScriptで複数の要素を取得!getElementsByClassName()とquerySelectorAll()の違い

f:id:endoakak:20200725103727j:plain

JavaScriptで同じクラス名の要素をまとめて取ってくる方法としてgetElementsByClassName()querySelectorAll()がありますが、どういう違いがあるのか気になって調べてみたのでまとめておきます。

どちらも複数の要素を取得する

これらのメソッドはそれぞれ次のような形で要素をまとめて取得します。

getElemntsByClassName -> HTMLCollection
querySelectorALL -> NodeList

こんな感じで使います。

<body>
  <div class="box"></div>
  <div class="box"></div>
  <div class="box"></div>
</body>
const elements = document.getElementsByClassName("box")
const list = document.querySelectorAll(".box")
console.log(elements)
console.log(list)

コンソールの出力結果はこちら。

f:id:endoakak:20200724093637p:plain

NodeListはforEachが使える

HTMLCollectionもNodeListも厳密には配列ではないので、配列に対して使えるメソッド(mapなど)は基本的には使えません。

しかし、NodeListだけはforEachが使えます。HTMLCollectionはforEachも使えません。

つまり、これはエラーになりますが、

const elements = document.getElementsByClassName("box")
elements.forEach(function(box) {
  //処理
})

これは可能です。

const list = document.querySelectorAll(".box")
list.forEach(function(box) {
  //処理
})

配列にしたければArray.from

なんだかめんどくさいHTMLCollectionとNodeListですが、Array.fromを使うことで、配列にすることが可能です。

const elements = document.getElementsByClassName("box")
elementsArray = Array.from(elements)
const list = document.querySelectorAll(".box")
listArray = Array.from(list)

これでOKです。

動的なHTMLCollectionと静的なNodeList

HTMLCollectionとNodeListの大きな違いが、HTMLCollectionは動的で、NodeListは静的だということです。

要素の取得後にHTMLに変化が起こった場合、HTMLCollectionには反映されますが、NodeListには反映されません。

例としてこのようなページを作成しました。

<body id="wrap">
  ブログ
  <div class="box"></div>
  <div class="box"></div>
  <div class="box" id="box_a"></div>
</body>
const wrap = document.getElementById("wrap")
const elements = document.getElementsByClassName("box")
const list = document.querySelectorAll(".box")

console.log(elements)
console.log(list)

wrap.addEventListener("click", function() {
  const box_a = document.getElementById("box_a")
  box_a.removeAttribute("class", "box")

  console.log(elements)
  console.log(list)
})

まずページが開かれた時点でHTMLCollectionとNodeListが取得され、コンソールに出力されます。

その後「ブログ」の文字をクリックするとid="box_a"のついたdivからclass="box"が取り除かれ、再びHTMLCollectionとNodeListを出力します。

実際に試してみるとこうなりました。

f:id:endoakak:20200724191013p:plain

上2段がはじめに出力され、下2段がクリック後に出力されたものです。HTMLCollectionからは要素が減っているのに対し、NodeListの要素は変わっていません。

まとめ

  • getElementsByClassName()ではHTMLCollectionという形で要素を取得
  • querySelectorAll()はNodeListという形で要素を取得
  • HTMLCollectionとNodeListは配列ではないが、Array.fromで配列にできる
  • HTMLCollectionはforEachが使えないが、NodeListは使える
  • HTMLCollectionは動的で、NodeListは静的