🍔

【JavaScript】Array.fill()で2次元配列を初期化するときに失敗した話

2023/01/18に公開

JavaScriptで配列を初期化するときにArray.fill()をよく使っていたのですが、自分の理解不足で間違った使い方をしていたことがあったので、メモを残しておきます。

2次元配列の初期化

2次元配列が作りたくて以下のようにnew Array(3).fill([])で初期化を行い、初めの要素に1を追加しました。私としては[ [ 1 ], [], [] ]と出力されてほしかったのですが、下記のような出力結果となりました。

const list = new Array(3).fill([]);
list[0].push(1);
console.log(list);

出力結果

[ [ 1 ], [ 1 ], [ 1 ] ]

全ての要素に同じものが追加されている(ように見えている)。

fillは引数がオブジェクトの場合、同じものを参照する

JavaScriptのリファレンスには以下のように書いてありました。

引数がオブジェクトの場合、同じオブジェクトを参照するみたいです。配列もオブジェクトと同じということでしょうか。
今回の場合はfill([])で追加した2次元配列の各[]は同じ参照先ということで、一つの[]に追加したつもりでも、配列は同じものを参照しているので、すべてに1が追加されたように見えているということだと思います。
一応以下のように確認したところtrueとなったため、そうだと思います。

const list = new Array(3).fill([]);
list[0].push(1);
console.log(list);
console.log(list[0]===list[1],list[1]===list[2]); // ←同じ参照先か確認

出力結果

[ [ 1 ], [ 1 ], [ 1 ] ]
true true

解決策

方法はいろいろあると思いますが、以下のように素直にループで回しました。

const list = new Array(3).fill([]);
for(let i = 0; i < 3; i++){
    list[i] = [];
}
list[0].push(1);
console.log(list);
console.log(list[0]===list[1],list[1]===list[2]); // ←同じ参照先か確認

出力結果

[ [ 1 ], [], [] ]
false false

ちゃんと勉強しないといけませんね。

参考サイト

Array.prototype.fill()

Discussion