JavaScriptのdelete演算子を配列に使うと起こる厄介な挙動
JavaScriptにおけるdelete演算子は、本来オブジェクトのプロパティを削除するための演算子です。
しかし、JavaScriptでは配列も「インデックスをキーとしたオブジェクト」の一種として扱われるため、実は配列に対してもdelete演算子を使用することができます。
ここで問題なのが、この使い方によって予想外の挙動が引き起こされるという点です。実際に見ていきましょう。
サンプルコード
まず、次のような配列リテラルを用意します。
const arr = ['a', 'b', 'c', 'd', 'e'];
この配列の末尾の要素(インデックス4)をdeleteで削除してみます。実行結果を予想しながら、以下のコードをご覧ください。
const arr = ['a', 'b', 'c', 'd', 'e']; delete arr[4]; console.log(arr); console.log(arr.length);
実行結果
このプログラムをコンソールで実行すると、次のように出力されます。
[ 'a', 'b', 'c', 'd', <1 empty item> ] 5
なぜこのような結果になるのか?
多くの方は、「1つの要素を削除したのだから、arr.lengthは5ではなく4になるはずだ」と予想したのではないでしょうか。
しかし実際には、delete演算子はその位置にある値だけをメモリ上から取り除くだけで、配列内の「スロット(場所)」そのものは残り続けます。
そのため、配列の長さ(length)はまったく変化せず、要素数は5のままです。ただし、1つ分のスロットが「空き(empty item)」として残り、いわゆる疎な配列(スパース配列)になってしまうのです。
要素を正しく削除したい場合の方法
配列から要素を完全に取り除き、lengthも適切に更新したい場合は、deleteではなく以下のメソッドを使うのが安全です。
splice():指定した位置の要素を取り除き、残りの要素を詰めてくれるpop()/shift():末尾・先頭の要素を取り除くfilter():条件に合わない要素を除外した新しい配列を生成する
例えば先ほどのケースなら、次のように書きます。
const arr = ['a', 'b', 'c', 'd', 'e']; arr.splice(4, 1); // インデックス4から1個の要素を削除 console.log(arr); // [ 'a', 'b', 'c', 'd' ] console.log(arr.length); // 4
このように、splice()を使えば配列が詰められ、lengthも4に正しく更新されます。
まとめ
delete演算子はあくまでオブジェクトのプロパティ削除用のものであり、配列に使うと値だけが消えて穴の開いた配列になります。lengthが変わらないためバグの温床にもなりやすいので、配列からの要素削除にはsplice()やfilter()などの専用メソッドを使うことを強くおすすめします。
-
JavaScriptの配列で使えるスプレッド演算子(...)の使い方
スプレッド構文(...)を使うと、配列などのイテラブルなオブジェクトを、0個以上の引数が期待される場所で展開することができます。これにより、配列の要素をまとめて関数の引数として渡すことが可能になります。スプレッド演算子の基本例えば、5つの引数を受け取る関数に対して5つの要素を持つ配列を渡したい場合、従来の書き方では各要素を個別に指定する必要がありました。しかし、スプレッド演算子を使えば「add(...arr)」のように記述するだけで、配列の各要素が順番に引数として展開されて渡されます。スプレッド演算子は、配列の結合やコピーなど、さまざまな場面でも活用できる便利な構文です。以下は、JavaScr
-
JavaScriptで配列の配列をオブジェクトに変換する方法
はじめにJavaScriptでは、「キーと値のペア」を格納した配列の配列(ネストされた配列)を、扱いやすいオブジェクトへ変換したい場面がよくあります。本記事では、その具体的な実装方法をわかりやすく解説します。例として、あるクリケット選手の成績データを表す次のような配列の配列を想定してみましょう。const arr = [ [Name, V Kohli], [Matches, 13], [Runs, 590], &nb