ノードとは何か
DOMの「ノード」は、HTML文書を構成する最小パーツのことです。要素(div、p、aなど)、テキスト(文字列)、コメント、属性など、画面に関係するすべてがノードとして木構造に並びます。ここが重要です:DOMは「要素だけの集まり」ではありません。文字の部分もコメントも属性も、全部ノードとして扱えるからこそ、細かい制御が可能になります。
代表的なノードの種類と違い(要素・テキスト・コメント)
要素ノード(Element)
HTMLタグそのもの。子ノードを持ち、属性(id、classなど)やスタイル、イベントを扱えます。
<h1 id="title">こんにちは</h1>
HTMLconst el = document.querySelector("#title"); // 要素ノード
console.log(el.tagName); // "H1"
console.log(el.id); // "title"
JavaScriptテキストノード(Text)
要素の中の“文字”部分。タグではなく純粋なテキストを持ち、空白もテキストとして存在します。
const el = document.querySelector("#title");
console.log(el.firstChild.nodeType); // 3(Text)
console.log(el.firstChild.nodeValue); // "こんにちは"
JavaScriptコメントノード(Comment)
HTML中のコメント。通常は画面に表示されませんが、解析やテンプレートのヒントに使われることがあります。
<!-- メモ: ここに説明文を追加 -->
<p>本文</p>
HTMLconst walker = document.createTreeWalker(document, NodeFilter.SHOW_COMMENT);
const comment = walker.nextNode();
console.log(comment.nodeValue); // "メモ: ここに説明文を追加"
JavaScriptここが重要です:操作したい対象が「要素」なのか「テキスト」なのかで使うプロパティ・メソッドが変わります。要素の文字を変えたいなら element.textContent(子のテキストをまとめて扱う)のほうが安全です。
ツリー構造と関係性(親子・兄弟・ルート)
親子関係
ノードは入れ子の木(ツリー)になっています。親(parentNode)、子(childNodes / children)、先頭・末尾の子(firstChild / lastChild)を辿れます。
const list = document.querySelector("ul");
console.log(list.parentNode); // 親ノード(例:body)
console.log(list.childNodes); // NodeList(テキストも含む)
console.log(list.children); // HTMLCollection(要素だけ)
JavaScript兄弟関係
同じ親を持つノードは兄弟です。次/前の兄弟を辿れます。
const item = document.querySelector("li");
console.log(item.nextSibling); // 次のノード(テキスト含む)
console.log(item.nextElementSibling); // 次の要素ノード
JavaScriptルート(document)
DOMツリーの根は document です。ここからすべてのノードへ到達できます。
ここが重要です:操作対象が「要素だけ」なのか「テキストも含む」なのかで、children と childNodes、nextElementSibling と nextSibling を使い分けます。意図しない空白テキストに引っかからないようにするのがコツです。
ノードの基本プロパティと違い(nodeType・nodeName・textContent)
nodeType(数値で種類判定)
- 要素は 1、テキストは 3、コメントは 8、ドキュメントは 9。
const n = document.querySelector("#title");
console.log(n.nodeType); // 1(要素)
JavaScriptnodeName / tagName(名前の読み取り)
- 要素では大文字タグ名(”DIV” など)。テキストやコメントでは
#text、#comment。
const el = document.querySelector("h1");
console.log(el.nodeName, el.tagName); // "H1" "H1"
console.log(el.firstChild.nodeName); // "#text"
JavaScripttextContent と innerHTML(内容の扱い)
- textContent: テキストとして安全に読み書き(タグは解釈しない)。
- innerHTML: 文字列のHTMLとして差し込み(タグが展開される)。
const p = document.querySelector("p");
p.textContent = "<b>安全に文字を入れる</b>"; // 画面にはそのまま文字
p.innerHTML = "<b>太字で表示</b>"; // HTMLとして解釈
JavaScriptここが重要です:ユーザー入力や外部データを入れるときは textContent を使うとXSSリスクを避けられます。innerHTMLは「信頼できる・限定的」な場面でのみ。
ノードの生成・挿入・削除(安全な組み立て方)
生成とテキストの追加
const li = document.createElement("li"); // 要素ノードを作る
li.textContent = "新しい項目"; // テキストノードをセット(自動生成)
JavaScript挿入(append / prepend / insertBefore)
const list = document.querySelector("ul");
list.append(li); // 末尾に追加(appendChildのモダン版)
JavaScript削除(remove / removeChild)
li.remove(); // 自分を親から取り外す
JavaScriptまとめて効率よく追加(フラグメント)
大量追加はフラグメントでバッチ化すると高速です。
const frag = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const li = document.createElement("li");
li.textContent = `Item ${i}`;
frag.append(li);
}
document.querySelector("ul").append(frag);
JavaScriptここが重要です:生成→内容設定→まとめて挿入の順にすると、再描画のコストを抑え、ちらつきや中途半端な状態を避けられます。
ノードの走査と選択の使い分け(ツリーウォークの勘どころ)
セレクタで直接取る(速くて実用的)
const items = document.querySelectorAll("ul > li.active");
JavaScriptTreeWalker / NodeIterator(種類で絞って辿る)
特定のノード種類だけを効率よく辿れます。
const walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT
);
let node;
while ((node = walker.nextNode())) {
// テキストノードだけ処理
}
JavaScriptここが重要です:CSSセレクタで十分な場面が大半ですが、「種類で厳密にフィルタして大量走査」するなら TreeWalker が役立ちます。
よくある落とし穴(テキストノード・空白・ライフサイクル)
- 空白がテキストノードとして存在するため、childNodes や nextSibling を使うと期待外のノードに当たることがあります。要素だけを扱うなら children / nextElementSibling を選ぶ。
- DOM生成前に要素を取得すると
null。deferやDOMContentLoadedを使い、DOM構築後に触る。 - innerHTML で大量挿入→再描画の負荷やイベントの解放漏れに注意。必要ならフラグメントや既存ノードの再利用を検討。
ここが重要です:どの種類のノードを扱うか、いつ扱うか、どのAPIで扱うか——この3点の意識が、安定したDOM操作の鍵になります。
まとめ
ノードはDOMの最小単位で、要素・テキスト・コメントなどがツリーを形作ります。要素を操作したいなら element中心のAPI(children、classList、textContent)を、文字やコメントまで扱いたいなら node中心のAPI(nodeType、nodeName、childNodes)を使い分けます。生成→設定→挿入の順で効率よく扱い、セレクタとTreeWalkerを適材適所で選ぶ。空白テキストやライフサイクルの落とし穴を避ければ、ノードの理解はDOM操作の強い土台になります。
