JavaScript Quiz: (new Array(2)).map($ => 'hello') === ?

まあ、分かってしまえばなんということはないんですが、結構面食らいますね。

MDNにはちゃんと書いてありました。

Array.prototype.map() - JavaScript | MDN

(callback) is not called for missing elements of the array (...) Due to the algorithm defined in the specification if the array which map was called upon is sparse, resulting array will also be sparse keeping same indices blank.

つまり、空要素に対してはcallbackは呼ばれず、配列のsparse状態(空要素があるという情報)も維持されるということなので、仕様どおりの挙動ではあります。

この「空要素(missing element)」はちょっと分かりにくいんですが、要素の置き場所だけが確保されていて実際には何の値も入っていないという要素です。式として評価すると undefined になります。こんなふうに:

console.log( (new Array(2))[0] === undefined ); // true

in 演算子だと空要素かどうかを調べられます。

console.log( 0 in (new Array(2) )); // false
console.log( 0 in [undefined] ); // true

そして Array.from(iterable)[...iterable] はこのsparse状態は保たず、undefined に変換してしまうようです。

console.log(new Array(2)); // [ <2 empty items> ]
console.log([...new Array(2)]); // [ undefined, undefined ]
console.log(Array.from(new Array(2))); // [ undefined, undefined ]

面白いですね!