要素の追加(appendChild, append, prepend, insertBefore)

以下では、DOM の「要素の追加」に関する 4 つの代表的メソッド — appendChild, append, prepend, insertBefore — を体系的に解説します。いずれも「既存ノードの子として新しいノードを挿入する」操作ですが、受け取れる引数・戻り値・挿入位置・例外発生条件などに違いがあります。


1. 共通の基本概念

  • 「追加」は原則 “移動”
    同じドキュメント中の既存ノードを追加すると、そのノードは元の位置から取り外され、新しい位置に移動します(複製はされません)。複製したい場合は node.cloneNode(true/false) を使います。

  • 再フロー・再描画
    追加のたびにレイアウト計算が発生し得ます。多数追加する場合は DocumentFragment の活用が有効です(後述)。

  • Node vs ParentNode

    • appendChild, insertBeforeNode インターフェースのメソッド(Element, Document, DocumentFragment などが使用可)。

    • append, prependParentNode ミックスイン由来で、Element, Document, DocumentFragment で使用可。


2. appendChild(node)

  • 構文

    js
    parent.appendChild(childNode)
  • 引数: Node(テキストを直接は渡せません。文字列を入れたい場合は document.createTextNode("...") を作って渡す)

  • 戻り値: 挿入された childNode(Node)

  • 挙動: parent末尾に 1 個のノードを追加

  • 例外

    • HierarchyRequestError: 親子関係として不正な組み合わせ

    • NotFoundError: 参照ノード(insertBefore の場合)や親が不正 など

  • 使用例

    html
    <ul id="list"><li>A</li></ul> <script> const li = document.createElement('li'); li.textContent = 'B'; document.getElementById('list').appendChild(li); // 末尾に <li>B</li> </script>

3. append(…nodesOrStrings)

  • 構文

    js
    parent.append(nodeOrString1, nodeOrString2, ...)
  • 引数: Node文字列複数渡せる(文字列は自動で Text ノード化)

  • 戻り値: なし(undefined)

  • 挙動: parent末尾に引数を左から順に追加

  • 強み

    • 文字列を直接渡せる

    • 複数を一度に追加できる(appendChild は 1 個ずつ)

  • 注意

    • IE など非常に古い環境では未対応(モダン環境では一般的に使用可)

  • 使用例

    html
    <div id="box"></div> <script> const em = document.createElement('em'); em.textContent = '強調'; document.getElementById('box').append('先頭テキスト ', em, ' 末尾テキスト'); // => <div>先頭テキスト <em>強調</em> 末尾テキスト</div> </script>

4. prepend(…nodesOrStrings)

  • 構文

    js
    parent.prepend(nodeOrString1, nodeOrString2, ...)
  • 引数: Node文字列 を複数

  • 戻り値: なし(undefined)

  • 挙動: parent先頭(最初の子の前)に引数を順に追加

  • 使用例

    html
    <ul id="menu"><li>既存1</li></ul> <script> const li = document.createElement('li'); li.textContent = '新規先頭'; document.getElementById('menu').prepend(li, ' テキストもOK'); // => <ul><li>新規先頭</li> テキストもOK<li>既存1</li></ul> </script>

5. insertBefore(newNode, referenceNode)

  • 構文

    js
    parent.insertBefore(newNode, referenceNode)
  • 引数

    • newNode: 追加したい Node

    • referenceNode: parent子でなければならない参照ノード

  • 戻り値: 挿入された newNode(Node)

  • 挙動: referenceNode直前newNode を追加

  • 特殊ケース

    • referenceNodenull を渡すと appendChild(newNode) と同等(末尾に追加)

  • 例外

    • NotFoundError: referenceNodeparent の子でない

    • HierarchyRequestError: 不正な親子関係

  • 使用例(任意の位置に挿入)

    html
    <ol id="steps"><li>1</li><li id="ref">3</li></ol> <script> const li = document.createElement('li'); li.textContent = '2'; const parent = document.getElementById('steps'); const ref = document.getElementById('ref'); parent.insertBefore(li, ref); // <li>3</li> の直前に <li>2</li> </script>
  • 「直後に挿入(insertAfter)」相当
    insertAfter は存在しません。以下のように nextSibling を使います。

    js
    parent.insertBefore(newNode, referenceNode.nextSibling);

6. 使い分けの早見表

目的 / 性質 appendChild append prepend insertBefore
末尾に追加 参照が null なら可
先頭に追加 参照に firstChild を渡す
文字列を直接渡せる × ×
複数引数で一括追加 × ×
戻り値(挿入ノードを返す) × ×
厳密な例外でのエラー検出がしやすい
任意位置に挿入(基準ノードの前) △(不可) △(不可) △(不可)
  • 実務指針

    • 末尾に数個・文字列もまとめて」→ append

    • 先頭に追加」→ prepend

    • 戻り値が必要厳密な検証をしたい」→ appendChild / insertBefore

    • 特定ノードの直前に入れたい」→ insertBefore


7. DocumentFragment でまとめて高速追加

多数のノードを 1 回で追加して reflow を抑えるテクニックです。

html
<ul id="list"></ul> <script> const frag = document.createDocumentFragment(); for (let i = 1; i <= 1000; i++) { const li = document.createElement('li'); li.textContent = `項目 ${i}`; frag.appendChild(li); // ここでは reflow しない } document.getElementById('list').appendChild(frag); // ここで一度に挿入 </script>

append/prepend でも frag をそのまま渡せます。


8. よくある注意点・落とし穴

  1. テキスト vs HTML
    テキストを挿入したいだけなら append("text") で十分です。HTML を解釈させて挿入したいなら innerHTML を使いますが、XSS の危険があるため、外部入力をそのまま入れないこと。安全に HTML を組み立てるなら createElement + プロパティ設定 を基本にします。

  2. 参照ノードの所属insertBefore
    referenceNode は必ず parent実子である必要があります。そうでないと NotFoundError

  3. ノードの“所有ドキュメント”
    別ドキュメント(iframe など)から持ってきたノードは、通常自動でインポートされますが、環境によっては document.importNode() が必要な場面があり得ます。

  4. 同一ノードの再追加は移動になる
    既存の li を別の場所に appendChild すると、元の場所から消えて新しい場所へ移ります。複数箇所に同じものを置きたい場合は cloneNode(true) を使います。


9. 具体例まとめ

9.1 末尾に複数・文字列も一括(append)

html
<div id="log"></div> <script> const time = document.createElement('time'); time.dateTime = new Date().toISOString(); time.textContent = '記録時刻'; document.getElementById('log').append('開始: ', time, ' / 完了'); </script>

9.2 先頭に見出しを追加(prepend)

html
<section id="article"> <p>本文…</p> </section> <script> const h2 = document.createElement('h2'); h2.textContent = '概要'; document.getElementById('article').prepend(h2); </script>

9.3 任意位置に 1 件挿入(insertBefore)

html
<ul id="todo"> <li id="today">今日の作業</li> <li>明日の作業</li> </ul> <script> const urgent = document.createElement('li'); urgent.textContent = '至急対応'; const list = document.getElementById('todo'); const ref = document.getElementById('today'); list.insertBefore(urgent, ref); // 「今日の作業」の直前に挿入 </script>

9.4 旧来コードとの互換・戻り値が必要(appendChild)

html
<div id="box"></div> <script> const child = document.createElement('span'); child.textContent = '戻り値が欲しい'; const appended = document.getElementById('box').appendChild(child); console.log(appended === child); // true </script>

10. まとめ

  • 末尾へ柔軟に: append(文字列可・複数可・戻り値なし)

  • 先頭へ: prepend(文字列可・複数可・戻り値なし)

  • 厳密・戻り値必要: appendChild(1 ノードのみ・戻り値あり)

  • 任意位置: insertBefore(参照ノード直前・戻り値あり)

  • 大量追加は DocumentFragment でバッチ化し、性能と可読性を上げる。

ChatGPT5 生成日:2025/09/11