Карта JavaScript: Почему это не работает?

Я пытался создать некоторые случайные данные, используя карту. К моему удивлению, я не мог понять, почему этот код не работает.

Рассмотрим следующий фрагмент, который работает как ожидалось:

const empty = [undefined, undefined];
const rand = empty.map(item => Math.random());

Output: [0.4774752874308936, 0.8482276976659398]

Я попытался упростить бит и сделать следующее

const rand = Array(2).map(item => Math.random())

Output: [undefined × 2]

Я не понимаю, почему это происходит. Очевидно, что оба массива, генерируемые Array (n) и [], являются типичными массивами и имеют все прототипы.

Array(2) instanceof Array
true

[undefined, undefined] instanceof Array
true

Array.isArray(Array(2))
true

Array.isArray([undefined, undefined])
true

Может кто-нибудь указать, где я здесь не так?

Ответы

Ответ 1

Array(2) дает массив пустой с длиной 2. Массивы JavaScript по своей сути разрежены (в них могут быть дыры, потому что они вообще не массивы), и что Array(2) дает вам. Это выглядит так:

+−−−−−−−−−−−−−−+
|    (array)   |
+−−−−−−−−−−−−−−+
| length: 2    |
+−−−−−−−−−−−−−−+

тогда как ваш массив [undefined, undefined] выглядит следующим образом:

+−−−−−−−−−−−−−−+
|    (array)   |
+−−−−−−−−−−−−−−+
| length: 2    |
| 0: undefined |
| 1: undefined |
+−−−−−−−−−−−−−−+

map, forEach, и большинство (но не всех) связанных методов на Array.prototype только циклически просматривают фактические записи разреженного массива. Поскольку массив, возвращаемый Array(2), не имеет реальных записей, ваш обратный вызов никогда не вызывается.

ES2015 добавил Array#fill (и его можно отрегулировать), который вы можете использовать для заполнения массива:

const rand = Array(2).fill().map(Math.random)
console.log(rand);

Ответ 2

Вы можете посмотреть спецификации Array#map:

Он не вызывается для отсутствующих элементов массива (то есть индексов, которые никогда не были установлены, которые были удалены или которым никогда не назначено значение).

Вы можете использовать Array.apply для получения массива iterabel с картой.

console.log(Array.apply(null, { length: 2 }).map(Math.random));

Ответ 3

Это потому, что вы считаете, что Array(2) интерпретируется движком JavaScript примерно так: "Создайте объект массива с двумя записями, инициализированными значением по умолчанию, например 0 или undefined".

На самом деле, движок JavaScript создает новый объект и устанавливает его свойство length равным 2. Он не имеет никакого реального контента.

Проверьте этот простой пример:

var arr = new Array(2);
console.log(arr);

Ответ 4

Вы создаете массив, инициализированный с размером 2. Но в этих позициях нет никакого элемента. то вы делаете [undefined, undefined].map(item => Math.random())

У вас есть массив с двумя undefined элементами в нем.