JavaScriptの配列初期化

#はじめに
pythonやKotlinでは連続する数の配列などを以下のように簡単に生成することができます。

```Kotlin:Numbers.kt
//ラムダ式を用いた初期化
val x = Array(5, { it })
```

```Python:Numbers.py
#rangeを用いた初期化
x = list(range(0,5))
```

同様に偶数からなる配列は以下のように生成できます。

```Kotlin:EvenNumbers.kt
val x = Array(5, { it * 2 })
```

```Python:Numbers.py
#リスト内包表記
x = [x * 2 for x in range(0, 5)]
```

特にPythonのリスト内包表記を使うと短く書くことができます。今回はこのような配列の初期化をJavaScriptで試してみます。

#0で埋めた配列

```JavaScript:JavaScript
Array(5).fill(0) //[0, 0, 0, 0, 0]
new Array(5).fill(0) //これも可
```

JavaScriptの配列生成では`[]`を用いたリテラル表記が頻出ですが、コンストラクタを用いて生成することもできます。第一引数に配列の長さを指定します。
またJavaScriptの標準ビルトインオブジェクトの一部は、new演算子の省略が認められています。（ただし、new演算子を省略した場合に挙動が変わるものがあるので注意が必要です。）


#undefinedで埋めた配列
```JavaScript:JavaScript
Array(5).fill() //[undefined, undefined, undefined, undefined, undefined]
```

0埋めの亜種ですが、fillメソッドの引数を省略することでundefinedで埋めることができます。この形がこれ以降に紹介する派生パターンの基本となります。



ちなみにfillメソッドは必要なの？と感じますが、必要です。

```JavaScript:JavaScript
 Array(5) // [ <5 empty items> ]
```

このように、undefinedで埋められているわけではないことがわかります。これについては、MDNから引用します。
>これは arrayLength 分の空のスロットがある配列を意味します。スロットに実際の undefined 値があるわけではありません

#連番の配列

```JavaScript:JavaScript
Array(5).fill().map((_, i) => i) //[0, 1, 2, 3, 4]
```
undefined埋めの配列にmapメソッドを適用します。mapメソッドに与える関数の第二引数には配列のインデックスが渡されますので、これを返してやることで連番を生成します。

#連続する偶数の配列
```JavaScript:JavaScript
Array(5).fill().map((_, i) => i*2) //[0, 2, 4, 6, 8]

Array(5).fill().filter((_, i) => i*2).filter(v => v % 2 === 0) //[0, 2, 4]
Array(5).fill().map((_, i) => i).filter(v => v % 2 === 0) //上に同じ
```
mapメソッドやfilterメソッドを使うことで実現できます。mapのみで行う方法では配列の長さ（配列の長さが5）を指定、filterを用いる方法は範囲（配列の要素のとる値が0から5まで）を指定できます。

#二次元配列

```JavaScript:JavaScript
Array(5).fill().map(() => Array(5).fill(0))
//[ [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ] ]
```

0埋め配列の変形です。

以下はダメな例です。

```JavaScript:JavaScript
Array(5).fill(Array(5).fill(0))
//[ [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ],
//  [ 0, 0, 0, 0, 0 ] ]
```
このようにしてしまうと、内側の配列は全て同じ場所を参照する配列となってしまいます。つまり以下のように一箇所の値を変更すると他の部分まで変更されてしまいます。

```JavaScript:JavaScript
const x = Array(5).fill(Array(5).fill(0))
x[0][1] = 1
console.log(x)
//[ [ 0, 1, 0, 0, 0 ],
//  [ 0, 1, 0, 0, 0 ],
//  [ 0, 1, 0, 0, 0 ],
//  [ 0, 1, 0, 0, 0 ],
//  [ 0, 1, 0, 0, 0 ] ]
```

#他の作り方
##Array.from()を用いる方法
```JavaScript:JavaScript
Array.from(Array(5)) //[undefined, undefined, undefined, undefined, undefined]
Array.from(Array(5)).fill(0)  //[0, 0, 0, 0, 0]
Array.from(Array(5), (_, i) => i) //[0, 1, 2, 3, 4]
```

##Array()の代わりにオブジェクトを利用する方法
```JavaScript:JavaScript
Array.from({length:5}) //[undefined, undefined, undefined, undefined, undefined]
Array.from({length:5}).fill(0)  //[0, 0, 0, 0, 0]
Array.from({length:5}, (_, i) => i) //[0, 1, 2, 3, 4]
```
lengthプロパティを持つオブジェクトは、配列風のオブジェクトとみなされるため`Array.from()`で配列に変換可能です。

#連番の他の作り方
##Object.keys()と...を用いる方法
```JavaScript:JavaScript
Array.from(Array(5).keys()) //[0, 1, 2, 3, 4]
[...Array(5).keys()] //[0, 1, 2, 3, 4]
```
配列のキーを取得する`Object.keys()`を用います。`Array(5).keys()`はIteratorを返すのみですのでfor...in文などには用いることができますが、配列としては使えません。Iteratorを配列に変換すのために、`Array.from`またはスプレッド構文を用いています

#実用性は無い
##文字列から生成
```JavaScript:JavaScript
Array.from("0".repeat(5)).map(i => parseInt(i))
```

ちなみに以下のようにすると二番目にNaNが出てきます。原因がわからないのですが、わかる方がいらっしゃればご教授いただきたいです

```JavaScript:JavaScript
Array.from("0".repeat(5)).map(parseInt) //[ 0, NaN, 0, 0, 0 ] なぜ NaN ?
```
##ジェネレータで生成
```JavaScript:JavaScript
Array.from((function*(){for(let i = 0; i < 5; i++) yield i})())
```
コードゴルフみたい。


#まとめ
個人的には`Array(5).fill().map(...)`が好きですが、`Array.from(Array(5), ...)`もありかなという気がします。初投稿で拙い点が多々あったと思いますが、最後まで読んでいただきありがとうございました。٩( 'ω' )و