8.

JavaScript/jQueryで子要素を全削除|empty・replaceChildren・innerHTML

編集
この記事の要点
  • jQuery: $(el).empty()(子要素のみ削除) vs $(el).remove()(自身も削除)
  • Vanilla 最新: el.replaceChildren()(2020〜、最も推奨)
  • Vanilla 古典: el.innerHTML = ""(簡単だがイベントリスナーが残るブラウザあり)
  • 性能重視: while (el.firstChild) el.removeChild(el.firstChild) ループ
  • メモリリーク防止: 子要素にイベントリスナー / addEventListener を付けていたら明示削除推奨

子要素を削除する 5 つの方法

「リストをクリアして再描画」「モーダルの中身をリセット」など、子要素を全削除するシーンは頻出します。JavaScript には複数のやり方があり、性能・安全性・古い API か新しい API かで選択が変わります。

方法対応速度イベント残し備考
el.replaceChildren()2020〜★ 速いクリア現代の推奨
el.innerHTML = ''古くから速いクリアされない場合ありシンプル、最頻出
while + removeChild古くから速いクリア確実
$(el).empty()jQuery普通★ 自動クリアjQuery 利用時
$(el).remove()jQuery普通クリア自身も消える

方法1: replaceChildren()(モダン推奨)

// 子要素を全削除
const list = document.getElementById('list');
list.replaceChildren();

// 削除と差し替えを同時に
list.replaceChildren(
  Object.assign(document.createElement('li'), { textContent: 'New 1' }),
  Object.assign(document.createElement('li'), { textContent: 'New 2' }),
);

// 配列展開もできる
const items = ['A', 'B', 'C'].map(t => {
  const li = document.createElement('li');
  li.textContent = t;
  return li;
});
list.replaceChildren(...items);

Chrome 86 / Safari 14 / Firefox 78(2020 年〜)で利用可能。IE はサポートしませんが、現代では考慮不要です。

方法2: innerHTML = '' (最頻出)

const list = document.getElementById('list');
list.innerHTML = '';

// 注意: innerHTML はパースが入るので、信頼できない値を代入するのは XSS リスク
// 空文字なら問題なし

シンプルで分かりやすい反面、古いブラウザではイベントリスナーや関連オブジェクトの解放が不完全で、メモリリークの温床になることがありました。モダンブラウザでは概ね問題ないですが、後述の replaceChildren() を使うのが安全。

方法3: while + removeChild(古典)

const list = document.getElementById('list');

while (list.firstChild) {
  list.removeChild(list.firstChild);
}

// あるいは lastChild から
while (list.lastChild) {
  list.removeChild(list.lastChild);
}

すべてのブラウザで確実に動作します。性能も高く、長くベストプラクティスとされていました。今では replaceChildren() に置き換わっていますが、IE / 古い WebView を相手にするときは依然有効。

方法4: jQuery .empty() / .remove()

// 子要素のみ全削除(自身は残る)
$('#list').empty();

// 自身も含めて削除
$('#list').remove();

// .detach() は DOM から外すがデータ・イベントは保持(再 append 可能)
const $kept = $('#list').detach();
$('body').append($kept);

// 子要素だけ削除して新しい要素を入れる
$('#list').empty().append('<li>New 1</li><li>New 2</li>');

.empty() は jQuery が子孫の data / event を自動的に解放するためメモリリーク対策として優秀でした。Vanilla の場合は手動で removeEventListener しないと残るケースに注意。

性能比較(概念)

1 万要素削除のおおまかな速度感所要時間
replaceChildren()★ 最速クラス
innerHTML = ''速い(パース不要のため)
while + removeChild速い
1 つずつ removeChild(forEach)やや遅い(再描画フラッシュが入ることあり)
jQuery .empty()★ 一段遅い(イベント解放処理あり)

体感差は小規模(数百要素)では誤差ですが、数千〜数万になると replaceChildren() の優位が見えます。

メモリリーク防止のコツ

削除する前にイベントリスナーを明示的に外すと、循環参照によるリークを防げます:

// ❌ 削除しても closure 経由でリスナーが残るパターン
const btn = document.createElement('button');
btn.addEventListener('click', () => bigState.doSomething());
list.appendChild(btn);
// 後で list.innerHTML = '' しても、登録した {bigState} の参照が残る可能性

// ✅ 削除前にリスナーを外す
const handler = () => bigState.doSomething();
btn.addEventListener('click', handler);
btn._handler = handler;
// ...
btn.removeEventListener('click', btn._handler);
list.removeChild(btn);

// ✅ AbortController で一括解除
const ctrl = new AbortController();
btn.addEventListener('click', handler, { signal: ctrl.signal });
// 後で
ctrl.abort();    // 全リスナー解除
list.replaceChildren();

React / Vue / Svelte の場合

仮想 DOM / リアクティブ系のフレームワークは、状態を空配列にするだけで DOM の子要素削除を内部処理してくれます。直接 DOM を触る必要はありません。

// React
const [items, setItems] = useState([1, 2, 3]);
setItems([]);   // → 自動で子要素削除

// Vue
const items = ref([1, 2, 3]);
items.value = [];

// Svelte
let items = [1, 2, 3];
items = [];

テンプレートのリセット(よくある実装例)

function renderList(data) {
  const list = document.getElementById('list');

  // クリア
  list.replaceChildren();

  // テンプレート要素を複製して append
  const tpl = document.getElementById('item-tpl');
  for (const d of data) {
    const node = tpl.content.cloneNode(true);
    node.querySelector('.name').textContent = d.name;
    node.querySelector('.price').textContent = '¥' + d.price.toLocaleString();
    list.appendChild(node);
  }
}

renderList([{ name: 'Apple', price: 120 }, { name: 'Banana', price: 80 }]);

FAQ

Q: innerHTML = '' は遅い?
A: 空文字代入は HTML パース不要で十分高速です。「大量 HTML 文字列を innerHTML に代入」は遅い、というよく聞く話と混同しないこと。

Q: 削除した子要素を再利用したい
A: el.removeChild(child) で取り出した child をそのまま別の親に appendChild() できます。jQuery なら .detach()

Q: replaceChildren が古いブラウザで動かない
A: モダンブラウザのみ対応。IE 11 等を相手にする場合は while (el.firstChild) 方式にフォールバック。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 導入方法
  2. 文法
  3. HTML/CSS 操作・制御
  4. 要素の取得
  5. 値の取得
  6. jQuery で要素を追加(append / prepend / before / after / wrap)
  7. 値と要素の削除
  8. 子要素の削除
  9. 要素のコピー
  10. Ajax
  11. 項目をタッチ/クリックしてスライドさせる方法
  12. テキスト/セレクトボックス/ラジオボタン変更時のイベント
  13. パスワードを一時的に表示させる方法
  14. $(document).ready(function() { ...
  15. セレクトボックスにオプションを追加する方法

最近更新/作成されたページ