JavaScript | DOM 操作:DOM 基礎 – ドキュメントツリーの構造

JavaScript JavaScript
スポンサーリンク

ドキュメントツリーとは何か

ドキュメントツリーは、HTML文書を「ノード(要素・テキスト・コメント)」の入れ子で表した木構造です。最上位の document を根にして、htmlheadbody と階層が続き、各要素が子ノードを持ちます。ここが重要です:ブラウザはこのツリー(設計図)をもとに画面を描画します。ツリーを操作すると、画面が同期して更新されます。


基本構造の全体像(html・head・body とノードの役割)

ルートからの階層

  • document が根。直下に html 要素があり、その中に headbody が並びます。
  • head はメタ情報(titlemetalinkscript など)、body は画面に表示されるコンテンツ(h1pdiv など)を担います。

例:このHTMLのツリー

<!doctype html>
<html>
  <head>
    <title>ツリーの例</title>
  </head>
  <body>
    <h1 id="title">こんにちは</h1>
    <p class="msg">DOM は木構造です</p>
  </body>
</html>
HTML

この構造は「document → html → head/title、body/h1、p」という親子関係のツリーになります。h1 内の文字「こんにちは」はテキストノードとして h1 の子になります。


親子・兄弟・祖先の関係(ツリーの辿り方)

親子と兄弟を辿る

const h1 = document.querySelector("#title");

console.log(h1.parentNode.tagName);        // "BODY"(親)
console.log(h1.nextElementSibling.tagName); // "P"(次の兄弟:要素だけ)
console.log(h1.firstChild.nodeType);        // 3(テキストノード)
JavaScript

ここが重要です:要素だけを扱うときは childrennextElementSibling、テキストも含めて扱うときは childNodesnextSibling を使います。空白もテキストノードとして存在するため、用途に応じてAPIを選ぶのがコツです。


children と childNodes の違い(要素のみか、すべてか)

要素だけのコレクション

const body = document.body;
console.log(body.children);   // HTMLCollection(要素のみ)
JavaScript

すべてのノード(テキスト・コメントを含む)

console.log(body.childNodes); // NodeList(テキスト・コメントも含む)
JavaScript

ここが重要です:意図せず空白テキストに当たるとロジックが崩れます。「DOMをレイアウト単位で扱う」なら要素中心のAPI、「文字も分析したい」ならノード中心のAPIを使い分けましょう。


ツリーの構築と更新(作成・挿入・削除で形が変わる)

新規ノードの生成と挿入

const li = document.createElement("li");
li.textContent = "項目";

const ul = document.querySelector("ul");
ul.append(li);           // 末尾に追加(ツリーに組み込まれる)
JavaScript

ノードの削除

li.remove();             // 親から切り離され、ツリーから消える
JavaScript

大量追加はフラグメントで効率化

const frag = document.createDocumentFragment();
for (let i = 0; i < 500; i++) {
  const li = document.createElement("li");
  li.textContent = `Item ${i}`;
  frag.append(li);
}
ul.append(frag);         // まとめて挿入で再描画コストを削減
JavaScript

ここが重要です:生成→内容設定→挿入の順にすると、中途半端な状態が画面に出ず、再描画も少なく済みます。大量更新はフラグメントで“バッチ処理”にするのが定石です。


ツリーの走査と選択(最短経路で目的のノードへ)

CSSセレクタで直接選ぶ

const items = document.querySelectorAll("ul > li.active");
JavaScript

種類で絞る走査(TreeWalker)

const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
let node;
while ((node = walker.nextNode())) {
  // テキストノードだけを処理
}
JavaScript

ここが重要です:普段は querySelector(All) が最も実用的。大量に、かつ種類で厳密に絞って辿る必要があるときは TreeWalker/NodeIterator を使います。


レンダリングと性能の勘所(読み書きのバッチ化)

DOMの読み取り(サイズ、位置)と書き込み(挿入、属性変更)が交互に混ざると、ブラウザが何度もレイアウト計算・再描画を行い、パフォーマンスが落ちます。読み取りをまとめる、書き込みをまとめる、スタイル変更はクラス切り替えで一括適用する、アニメーションは requestAnimationFrame を使う——これらでツリー更新の負荷を抑えられます。ここが重要です:DOM操作は強力だが重い。更新の“塊”を作る意識が、滑らかなUIを支えます。


よくある落とし穴(空白テキスト・DOM構築タイミング)

  • 空白文字がテキストノードとして存在するため、childNodesnextSibling が意図しないノードを返すことがあります。要素だけなら childrennextElementSibling を使う。
  • DOM構築前に要素を参照すると nulldefer 属性を付けたスクリプトや、DOMContentLoaded イベントで「ツリーが完成してから」操作する。
  • innerHTML の乱用は、XSSやイベント喪失、再描画の負荷につながります。必要なときだけ、信頼できるデータに限定し、基本は要素生成・挿入で組み立てる。

ここが重要です:ツリーは「いつ」「何を」「どのAPIで」触るかで安定性が決まります。タイミングと対象の種類を意識し、意図通りに辿れる道具を選びましょう。


まとめ

ドキュメントツリーは、document を根とするノードの木構造で、htmlheadbody を軸に全要素・テキストが階層化されています。要素中心のAPI(children、classList、querySelector)とノード中心のAPI(childNodes、nodeType、TreeWalker)を使い分け、生成→設定→挿入で構造を安全に更新します。空白テキストやDOM構築タイミングの落とし穴を避け、読み書きのバッチ化で性能を守る——この感覚が身につくと、ツリーの全体像を手の内で扱えるようになります。

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