スポンサーリンク

JavaScriptの動かないコード (初級編) DOM要素の配列を,forループで順番に全削除できない


以下のJavaScriptコードが意図した動作をしないのは,なぜですか。(制限時間1分)


やりたい事:

  • DOM操作により,div要素を全て削除する。
<body>


<input type="button" value="DIV要素の削除を実行" onclick="f()">


<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>



<script>

function f()
{
	// 全要素を取得
	var arr = document.getElementsByTagName("div");
	
	for( var i = 0; i < arr.length; i ++ )
	{
		var elem = arr[i];
		
		// 一つずつ削除
		elem.parentNode.removeChild(elem);
	}
	
}

</script>


</body>

発生する問題

実行するたびに,全体のおよそ半分の要素が,削除されずに残ってしまう。

5つの要素がある場合は,3回削除するとすべて削除し終わる。

forループで全ての要素を削除しきれていない。


問題の原因と解決策

1つの要素を削除するたびに,後ろの要素が頭にずれこんできて,配列の長さが変わってしまう事が原因。

1つの要素をremoveChildすると,消えた分のインデックスに対して,その次の要素が入り込んでくるのだ。

だから,インデックスを頭から順番にスキャンするようなループだと,削除されずに要素が残ってしまう。


これを解決するには,forループをDOM要素のリストの後ろから(逆から)削除してゆけばよい。

for( var i = 0; i < arr.length; i ++ )

↓

for( var i = arr.length - 1; i >= 0; i -- )

これでOK。末尾から全要素を削除できる。


この現象は,Arrayのsplice()では発生しない。

普通の配列であれば,splice()で指定したインデックスの要素を削除しても,要素はundefinedになるだけ。

だから,消えた分の項目に後ろがずれこむ事はない。

下記のコードは安全に動作する。

<input type="button" value="実行" onclick="f()">



<script>

function f()
{
	var arr = [2,4,6,8,10];
	
	for( var i = 0; i < arr.length; i ++ )
	{
		arr.splice( i );
	}
	
	alert( arr.length ); // 0
	alert( arr.join(",") );
}

</script>

JavaScriptの配列の要素を削除する(delete演算子とspliceメソッド) | 山本隆の開発日誌
http://www.gesource.jp/weblog/?p=4112


getElementsByTagName parentNode.removeChild | JavaScriptのQ&A【OKWave】
http://okwave.jp/qa/q4620142.html

  • gg[0]をremoveすると、今までgg[1]だったオブジェクトがgg[0]に 格上げされます。 なのでループでgg[1]を削除するとそれはそれまでgg[2]だったものです その流れでひとつ置きに削除されていくわけです。 なので、この手の処理はけつから消していきます。


Javascriptの話。 :: ウェブデザイナーの日記
http://blog.3ot.net/design/javascript...

  • var num = e.childNodes.length; for(var i = 0; i < num; i++){ e.removeChild(e.firstChild); } }
  • e.childNodes.lengthでノード数を取得できるけど、そのままforの中に入れるんじゃなくて、変数に代入してからだとうまくいく

関連する記事:

JavaScriptの動かないコード (中級編) iframe内のDOM要素を別フレームにコピーできないエラー
http://language-and-engineering.hatenablog.jp/entry/20090214/p1


JavaScriptの動かないコード (中級編) innerHTMLを追記するとイベントハンドラが消える
http://language-and-engineering.hatenablog.jp/entry/20090903/p1


JavaScriptの動かないコード (中級編) cloneNodeで選択状態が変わるエラー
http://language-and-engineering.hatenablog.jp/entry/20080926/1222365534