🫠

Arrayコンストラクターとmapを使って任意の数の配列を作成する際に、fillが必要な理由を紐解く

2024/03/22に公開

皆さんこんにちは!
先月行われた武尊vsスーパーレックの試合観ましたか??(この試合最高に面白かったです)
趣味でキックボクシングをやっていますが、スーパーレックの強烈なローキックを見てからマススパーリングなどでローキックを出せるように日々練習しています🔥
↓↓まだ観てない方は是非!
https://www.youtube.com/shorts/y2a0xFw7ObE

ということで本題に入ります!笑

Arrayコンストラクターとmapを使って任意の数の配列を作成する場合、fillメソッドがないと意図した挙動にならない問題

Arrayコンストラクターとmapを使って1~7の数字が入ってる配列を作成する場合、以下のように記述すると、何も入っていない配列ができてしまいます。

new Array(7).map((_, index) => index + 1)
// [ <7 empty items> ]

調べてみると、fillメソッドを使うことで意図した挙動になってくれます。

new Array(7).fill().map((_, index) => index + 1)
// [1, 2, 3, 4, 5, 6, 7]

とりあえず意図した挙動になってくれたものの「fillって何してるの?」「fillがなくても1~7が入った配列が作成できそうなのになぜできないのか?」と疑問に思ったので深ぼっていきたいと思います。

なぜnew Array(7).mapの結果が[ <7 empty items> ]になるのか

まずArrayコンストラクターについて調べてみます。
Arrayコンストラクターに値を渡すと以下のように、値は空ですが、lenghtが7となっていました。

MDNを読んでみると以下のような記述が...!

Array コンストラクターに渡された唯一の引数が 0 から 232-1 の間(両端を含む)の整数であった場合は、新しい JavaScript の配列を返し、その length プロパティがその値になります(メモ: これは arrayLength 個の空のスロットを持つ配列であり、実際に undefined の値が入ったスロットではありません。疎配列を参照してください)。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/Array

なるほど、Arrayコンストラクターに値を渡すと、undefinedですらない配列が生成されてたんですね。
(※配列の中に空のスロットがある配列のことを疎配列というみたいですね。)

今度はmapメソッドのMDNを読んでみます。

callbackFn は値が割り当てられている配列インデックスに対してのみ呼び出されます。疎配列で空のスロットに対しては呼び出されません。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map
mapメソッドのコールバック関数は、疎配列に関しては呼び出されないようです。
なので、new Array(7).mapの結果が[ <7 empty items> ]になっていたんですね。

なぜfillメソッドを使うと意図した挙動になるのか

fillのMDNを見てみると...

fill() メソッドは疎配列の空のスロットを、 value で埋めます。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/fill
空のスロットをvalueで埋めてくれると書いてありますね。
試しに以下のコードを実行してみます。

new Array(7).fill()
// [undefined, undefined, undefined, undefined, undefined, undefined, undefined]

new Array(7).fill(null)
// [null, null, null, null, null, null, null]

fillメソッドを使うことで、値が入るようになりましたね!
上記の通り、fillの引数に何も指定しないとundefinedが入り、指定すると指定したものが入るようになりました。

整理すると、以下のコードは7つのundefinedが入った配列に対して、mapメソッドを実行してるので、1~7までの値が入った配列が返るようになってたんですね!

new Array(7).fill().map((_, index) => index + 1)

ちなみにコードレビューをしていただいた際に、[...Array(7).keys()].map()でも書けるとご指摘をいただきました!

keysのMDNを読んでみると以下のように書いてありました!

疎配列で使用した場合、 keys() メソッドは空のスロットを undefined という値があるかのように反復処理します。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/keys

なるほど、Arrayコンストラクターでできた疎配列をundefinedがあるかのように振る舞ってくれるので、結果以下のようになるんですね!
確かにkeysの方が直感的に書けていいなと思いました🙏

[...Array(7).keys()]
// [0, 1, 2, 3, 4, 5, 6]

最後に

では最後に宣伝です!
スペースマーケットでは、一緒にサービスを成長させていく仲間を探しています。
とりあえずどんなことをしているのか聞いてみたいという方も大歓迎です!
ご興味ありましたら是非ご覧ください!
https://www.wantedly.com/projects/1113570
https://www.wantedly.com/projects/1113544
https://www.wantedly.com/projects/1061116
https://spacemarket.co.jp/recruit/engineer/

スペースマーケット Engineer Blog

Discussion