
最初に結論なんだけど、たぶん [...Array(length)].map(fn) が良いかなと。
const arr = [...Array(3)].map((_, i) => i); console.log(arr); // => [ 0, 1, 2 ] console.log(arr.length); // => 3
... で展開
配列オブジェクトは反復可能 (iterable) なので、スプレッド構文 ... で展開してやることができます。
const arr = [...Array(3)]; console.log(arr); // => [ undefined, undefined, undefined ] console.log(arr.length); // => 3
短いし良さそう。
ただ記号の組み合わせになるので、初見でぎょっとするかも? すぐ慣れるとは思うけれど。
map() と組み合わせて初期値
初期値も設定できます。初期値じゃないけど実質初期値。
const arr = [...Array(3)].map(() => 0); console.log(arr); // => [ 0, 0, 0 ]
オブジェクトを初期値にする場合は注意
オブジェクトを作る場合、丸括弧 () で括るのを忘れないように。 => に続けて波括弧 {} を書くと違う意味になるので。
const arr = [...Array(3)].map((_, i) => { id: i + 1 });
console.log(arr); // => [ undefined, undefined, undefined ]
const arr = [...Array(3)].map((_, i) => ({ id: i + 1 }));
console.log(arr); // => [ { id: 1 }, { id: 2 }, { id: 3 } ]
他のやり方も同じね。
new Array(length)
これが一番素直なやりかたではあるが、項目が空になってしまうという問題がある。
const arr = Array(3);
console.log(arr); // => [ <3 empty items> ]
arr.forEach((value) => {
console.log(value); // ←一度も呼ばれない
});
ここでいう空は undefined が入っているわけではなく本当に空なので、 forEach() や map() が利きません。
というわけでだいたいの場合、こいつを起点にしてもうちょっとずつコードをこねこねしてやる必要があります。
new
はあってもなくても同じです。
const arr = new Array(3);
詳しくはこちら。
Array.from()
初見のわかりやすさならこちらか。
const arr = Array.from({ length: 3 });
console.log(arr); // => [ undefined, undefined, undefined ]
console.log(arr.length); // => 3
可読性は悪くないが、ちょっと記述量が多いような?
初期値で埋める
第2引数へマップ関数与えられるので、 undefined 以外を設定したい場合に大変便利。
const arr = Array.from({ length: 3 }, () => 0);
console.log(arr); // => [ 0, 0, 0 ]
fill()
map() 等は空の項目を飛ばすんだけど、 fill() は飛ばさずに埋めてくれます。
const arr = Array(3).fill(0); console.log(arr); // => [ 0, 0, 0 ] console.log(arr.length); // => 3
undefined 以外にも任意の値で生成できるし、ハック的な不明瞭さもないし、良いんじゃないすかね。
ただし、オブジェクトを入れるのはだめです。
オブジェクトで埋めちゃだめ
各要素が同じオブジェクトのインスタンスを指してしまいます。
const arr = Array(3).fill({ a: 1 });
arr[0].a = 2;
console.log(arr[0]); // => { a: 2 }
console.log(arr[1]); // => { a: 2 }
console.log(arr[0] === arr[1]); // => true
というわけで、やるならこう。
const arr = Array(3).fill().map(() => ({ a: 1 }));
結局長くなってしまった。 しかもメソッドを連鎖して呼び出すので、一行で書くには見た目がちょっと。
join() からの split()
一度文字列に変換してから、配列へ再変換します。
const arr = Array(3).join(',').split(',');
console.log(arr); // => [ '', '', '' ]
console.log(arr.length); // => 3
要素は空文字列 '' になります。
二段階あるのがハックっぽくて可読性低め。
apply()
関数オブジェクトのメソッド apply() です。
const arr = Array.apply(null, Array(3)); console.log(arr.length); // => 3 console.log(arr); // => [ undefined, undefined, undefined ]
利点は古い環境でも使えるところ。
for で頑張る
いやあこれはちょっと。
const arr = Array(3);
for (let i = 0; i < arr.length; i++) {
arr[i] = undefined;
}
console.log(arr); // => [ undefined, undefined, undefined ]
console.log(arr.length); // => 3
おしまい
というわけで、 [...Array(3)].map(fn) がよろしいかと存じます。
関連
- 配列のコンストラクターを改めて見てみる(配列とかおれおれAdvent Calendar2018 – 01日目)
- 配列風オブジェクトをArray.from()で本物の配列へ変換。(配列とかおれおれAdvent Calendar2018 – 05日目)
- 配列初期化子 [] のひみつ。(配列とかおれおれAdvent Calendar2018 – 09日目)