JavaScript の Array で要素を削除する

Javascript の Array で,delete を使ったあとに push で要素の追加をする,ということを繰替えすと,添字の最大値 (length) がどんどん増えていく.delete しても添字の詰めなおしがおこなわれず,length の値は減らない.

var arr = new Array();

arr.push("test0");
arr.push("test1");
alert(arr.length); // 2 が表示される.

delete arr[0];
alert(arr.length); // 2 が表示される.

arr.push("test2");
alert(arr.length); // 3 が表示される.

delete arr[0];
alert(arr[0]); // undefined が表示される

delete arr[2];
arr.push("test3");
for ( var i = 0; i < arr.length; i++ )
{
    alert(arr[i]);
} // undefined, test1, undefined, test3 と表示される

for ( var i in arr )
{
    alert(arr[i]);
} // test1, test3 と表示される

こんなかんじで delete することで,みかけ上は可変長配列のように使えてるけど,添字の詰めなおしはされてないのがわかる.というか,delete はそもそもプロパティを消すだけなので,詰めなおし操作がされるわけもない.要素を削除したときに詰めなおしもしたければ splice() を使う.

var arr = new Array();

arr.push("test0");
arr.push("test1");
alert(arr.length); // 2 が表示される.

arr.splice(0,1);
alert(arr.length); // 1 が表示される.

arr.push("test2");
alert(arr.length); // 2 が表示される.

arr.splice(0,1);
alert(arr[0]); // test2 が表示される

arr.splice(0,1);
arr.push("test3");
for ( var i = 0; i < arr.length; i++ )
{
    alert(arr[i]);
} // test3 だけが表示される

添字の最大値が増えまくることを気にしないなら,delete を使っても見掛け上は可変長配列であるかのように使える.delete arr[0] としても,arr.0 というプロパティが削除されるだけで,プロパティを 0 から順番に付けなおしているわけじゃないということ.

また,delete したプロパティを表示させようとすると undefined と表示されるけど,undefined を要素に代入する,というのとはまた違う,

var arr = new Array();

arr.push("test0");
arr.push("test1");
alert(arr.length); // 2 が表示される.

arr[0] = undefined;
alert(arr.length); // 2 が表示される.

arr.push("test2");
alert(arr.length); // 3 が表示される.

arr[0] = undefined;
alert(arr[0]); // undefined が表示される

arr[2] = undefined;
arr.push("test3");
for ( var i = 0; i < arr.length; i++ )
{
    alert(arr[i]);
} // undefined, test1, undefined, test3 と表示される

for ( var i in arr )
{
    alert(arr[i]);
} // undefined, test1, undefined, test3 と表示される

delete する場合とくらべると,最後の for 文の動作がかわる.delete すると arr のプロパティ自体が削除されるから,for でプロパティを列挙したときには,delete されているプロパティが出てこない.undefined を代入しただけでは,プロパティは削除されていないので for で列挙すると出てくる.なかなかややこしい.そもそも Array が,連想配列の添字に通し番号を使うことで,あたかも他言語の配列のように扱えるようにしているだけ,ということを知っていないと,こういう動作になることは理解しにくいよね多分.

もうひとつ,存在していないプロパティを参照したときに,結果が必ずしもエラーになるわけでなく,undefined を返すことがある(エラーになることもある),というところも関係しているのがややこしい.delete arr[0] すると,arr.0 というプロパティは削除されているけど,arr.0 を参照すると undefined が返ってくる.arr[0] = undefined というように直接 undefined を代入すると,arr.0 というプロパティは存在しているのに,arr.0 を参照すると undefined が返ってくる.undefined ではプロパティの存在自体を調べることはできず,厳密に調べたければ in 演算子を使う必要があるぽい.