【JavaScript】querySelectorで要素を取得する方法

javascript-icon JavaScript

こんにちは、かつコーチです。

前回はDOMの仕組みについて解説し、DOM操作は「要素を取得する」→「要素を操作する」の2ステップが基本だとお伝えしました。

今回はその1ステップ目、「目的の要素をどうやって探し出すか」を扱っていきます。

要素の取得方法にはいくつか種類がありますが、その中でも今主流になっている querySelector を中心に見ていきましょう。

要素を取得する方法は複数ある

昔からある取得方法

JavaScriptには、実は querySelector が登場する前から使われている取得方法があります。

代表的なのが getElementByIdgetElementsByClassName です。

<div id="header">ヘッダーです</div>
<p class="text">本文です</p>
const header = document.getElementById("header");
console.log(header.textContent);
// "ヘッダーです"

const texts = document.getElementsByClassName("text");
console.log(texts[0].textContent);
// "本文です"

getElementById はid属性の値、getElementsByClassName はclass属性の値を指定して要素を取得します。

古くからある分、対応しているブラウザが非常に多いというメリットがあります。

CSSセレクタで取得できるquerySelector

一方 querySelector は、CSSのセレクタと同じ書き方で要素を取得できる、比較的新しい方法です。

const header = document.querySelector("#header");
console.log(header.textContent);
// "ヘッダーです"

const text = document.querySelector(".text");
console.log(text.textContent);
// "本文です"

id属性を指定するときは # を、class属性を指定するときは . を、CSSと同じルールでつけるだけです。

タグ名だけを指定したり、親子関係を指定したりすることもできます。

const firstParagraph = document.querySelector("p");
// ページ内で最初に見つかった<p>要素

const nested = document.querySelector("div.card > p.title");
// class="card"のdivの直下にある、class="title"のp要素

CSSを書いたことがある人であれば、この書き方の方がとっつきやすいはずです。

querySelectorとquerySelectorAllの違い

1つだけ取得するか、複数取得するか

querySelector は、条件に合う要素のうち最初の1つだけを返します。

ページの中に同じclassを持つ要素が複数あっても、querySelector では最初の1つしか取得できません。

複数の要素をまとめて取得したい場合は、querySelectorAll を使います。

<ul>
  <li class="item">りんご</li>
  <li class="item">みかん</li>
  <li class="item">ぶどう</li>
</ul>
const first = document.querySelector(".item");
console.log(first.textContent);
// "りんご"(最初の1つだけ)

const all = document.querySelectorAll(".item");
console.log(all.length);
// 3(全部で3件)

all.forEach(function (item) {
  console.log(item.textContent);
});
// りんご
// みかん
// ぶどう

querySelectorAll は、forEach で1件ずつ処理できる NodeList という形式で結果を返してくれるのが特徴です。

つまずきポイント:NodeListは配列そのものではない

ここで私が実際につまずいた経験があります。

querySelectorAll の戻り値であるNodeListに対して、配列専用のメソッドを使おうとしてエラーになったことがありました。

❌ Before:NodeListに配列のmapメソッドを使おうとしてエラーになる

const items = document.querySelectorAll(".item");

const texts = items.map(function (item) {
  return item.textContent;
});
// Uncaught TypeError: items.map is not a function

NodeListは配列に「似ている」データ構造ですが、配列そのものではありません。

そのため、mapfilter といった配列専用のメソッドをそのまま呼び出すとエラーになってしまいます。

✅ After:Array.fromで配列に変換してからmapを使う

const items = document.querySelectorAll(".item");

const texts = Array.from(items).map(function (item) {
  return item.textContent;
});

console.log(texts);
// ["りんご", "みかん", "ぶどう"]

Array.from() を使ってNodeListを配列に変換すれば、mapfilter といった配列のメソッドを問題なく使えるようになります。

このエラーで30分近く原因を探した記憶があり、それ以来「NodeListは配列じゃない」と自分に言い聞かせるようにしています。

querySelectorとgetElementByIdなどの使い分け

どちらを使えばいいのか

「結局どちらを使えばいいの?」と迷う人も多いので、判断軸を整理しておきます。

取得方法書き方取得件数
getElementByIdid属性名のみ1件
getElementsByClassNameclass属性名のみ複数(HTMLCollection)
querySelectorCSSセレクタ全般1件(最初のみ)
querySelectorAllCSSセレクタ全般複数(NodeList)

これから新しくコードを書くのであれば、基本的に querySelectorquerySelectorAll を使えば十分です。

CSSセレクタの書き方さえ覚えておけば、id・class・タグ名・親子関係など、あらゆる条件を同じ書き方で指定できるためです。

ただし、既存のコードを読むときには getElementById もよく登場するので、両方の書き方を知っておくと安心です。

HTMLCollectionとNodeListの違いにも注意

余談ですが、getElementsByClassName が返すHTMLCollectionは、NodeListともまた少し性質が異なります。

HTMLCollectionは「ライブ(live)」なコレクションで、DOMの変化にあわせて中身が自動的に更新されます。

一方 querySelectorAll が返すNodeListは「静的(static)」で、取得した時点のスナップショットのままです。

初心者のうちは深く気にしなくても大丈夫ですが、「後から要素を追加・削除するコードで挙動が変わることがある」ということだけ頭の片隅に置いておいてください。

まとめ

この記事のポイント

  • querySelector はCSSセレクタと同じ書き方で要素を取得できる
  • querySelector は最初の1件のみ、querySelectorAll は複数件をNodeListで取得する
  • NodeListは配列に似ているが配列ではないため、map などを使うには Array.from() で変換する
  • 迷ったら querySelector / querySelectorAll を基本の選択肢にする
  • getElementsByClassName が返すHTMLCollectionは、DOMの変化に追従する「ライブ」なコレクションである

次に読むべき記事

要素を取得できるようになったところで、次回はその要素を「追加」「削除」する方法を解説します。

→ 次の記事:要素の追加・削除(createElement, appendChild等)

タイトルとURLをコピーしました