読者です 読者をやめる 読者になる 読者になる

見つけたことをぶん投げる所

jsをメインとした記事を投げる予定。qiitaでやれ事案

javascriptで配列を自由に初期化

例えば、javascriptにおいて [ 0,1,2,3,4,5,6 ] のような配列を作りたい時があります。
当然これと全く同じ配列をいつも作りたいのであれば直接書けばいいですが、
要素個数が未定である時はこの方法は一般的な表現になってなくてよろしくないです。

今回は、この配列の生成をjavascriptにおいて関数型チックに書く方法を紹介します。

結論

最初に結論を書いてしまいますが、以下のように書けば良いです。

// [ 0,1,2,3,4,5,6 ]
var myAry = Array.apply(null, { length:7 }).map(function (undef, i) {
    return i;
});

なぜこれで動作するのか説明

本当は、Array(7).map(function () { ... }); みたいに書ければ良いんですが、
それは [,,,,,,].map(...) ってことになります。
実は javascript は、要素の中身が空の場合は.map()などは動きません。
もちろん、[undefined, undefined, ...].map(...) のように書けば動きます
ということは、ミソはこの[undefined, undefined, ...]というような配列を用意することとなります。

あと、前知識として、Function.prototype.apply() の説明をします。
大したものじゃないので、仕様がなんとなくわかる場合は読み飛ばしてください。
以下の関数があったとします:

function minus(a, b) {
    return a - b;
}

この関数の呼び方についてですが、続けて下も見てみてください。

console.log(minus(2, 3)); // -1
console.log(minus.apply(null, [2, 3]); // -1

apply は、文字通り関数を呼び出すメソッドです。
第一引数のもつメソッドとして、元の関数を呼び出そうとします。
今回は特に指定する必要がないのでnullにしました。別に何だっていいです
大事なのは第二引数です。.apply()を使うと、上のコードの通り引数たちを配列にして渡せます。

本題に戻りましょう。 ここで Array(1,2,3,5)[ 1,2,3,5 ]が等価であることを思い出しましょう。
ということは、Array.apply(null, [,,])とすれば[undefined, undefined, undefined]が作り出せます。
この場合は、配列の中身が空でも問題ないです。
一般性を保つには、Array.apply(null, Array(7))とかですかね。

でもこの方法だと引数で配列を作っていて、メモリがもったいないですねー
(関数型だとどうせメモリの無駄遣いをしてしまいますが)
解決策はこうです:

Array.apply(null, { length:4 }) // [undefined, undefined, undefined, undefined]

実は length プロパティさえあれば何でもいいっぽいですね。。。
ここまでできればあとは.map()するだけです

その他比較

他言語ならもっと簡潔に書けることは多いです。
下は ruby の場合の書き方です

Array.new(7) { |i| i } #=> [ 0,1,2,3,4,5,6 ]

(0..6).to_a #=> [ 0,1,2,3,4,5,6 ] alluser さんのコメントを参考に追加

(0..6).map{|v| 3 * v} #=> [0, 3, 6, 9, 12, 15, 18]    追加
([0]*7).map.with_index{ |v, i| 3 * i } #=> [0, 3, 6, 9, 12, 15, 18]    追加

ちょっと考えたら色々あった...この言語自由度高いなあ

coffeescript ならこうです。

[0...3].map (e) -> Math.random()
#=> [ 0.2867903469596095, 0.7377240755595267, 0.5721909941311419 ]

ary = (i + Math.random() for i in [0...3])
#=> [ 0.10734258475713432, 1.5030816949438304, 2.5735190827399492 ]