Posted at

Array.lengthやnew Array()で作られた配列の空要素はundefinedではない

ちょっと嵌ったので。


起こったこと

配列の要素が一定数以下だった場合に空の時用の要素で補充しようとして以下のようなコードを書きました。

if(someArray.length < THRESHOLD){

someArray.length = THRESHOLD;
someArray.map((element) => {
if(element){
return element;
}
return forEmpty;
})
}

普通のwhileやforが使いたくなかったのでこう書いたわけですが、実はこのコードは正しく動きません。

Array.lengthに追加された分の要素については、mapによる変換が行われずのままです。


配列の空要素には何が入っている?

Array.lengthで拡張した配列や、new Array(数値)で作成した配列、宣言時に[,,]というような形で値を指定しなかったような配列。

これらの空いている要素に入っている値は何でしょうか。

実際にIndexを指定してアクセスしてみるとundefinedが返ってくるので、undefinedだと私は思っていました。

が、実際は「何も入っていない」が正解です。

実際、コンソール等で表示させてみると、エンジンによって若干表示は異なりますがemptyとかそういう形の表示がされます。


何も入っていないものを高階関数は無視する

とはいえ、「何も入っていない」ものに対してアクセスするとほぼすべてのケースでundefinedが返るので、ほとんどの場合はundefinedと同一視して問題ありません。

(for of,[Symbol.iterator],スプレッド構文による展開辺りもundefinedとして扱われる)。

ただし、Arrayの標準組み込みの高階関数群(forEach,map,reduceなど)に関してはこの「何も入っていない」ものを無視して処理する仕様になっています。

(ただし、indexが詰まることなどはなく、コールバック関数に渡る第二引数の値は「何も入っていない」ものも存在する前提でのindexになります)

正直、意義がよく分からない仕様です。


undefinedとして扱いたい場合は?


  • 素直にforループやiteratorを使う

  • [...array].map など一度スプレッド構文で空要素をundefinedに変換してから使う

  • 使う前にfillなどで要素を詰める(どこが空いているのか明らかな場合)