Выделить новый массив в javascript

Попытка выделить новый массив со значениями.

Случай 1:

var x = new Array(3).map(()=>1);

Теперь x есть [undefined * 3]

Случай 2:

var x = [...new Array(3)].map(()=>1);

И теперь x есть [1,1,1]

Может ли кто-нибудь помочь здесь?

Почему использование этого оператора с расширением делает такую ​​разницу?

И почему Case 1 не работает?

Ответ 1

tl; dr: Первый массив имеет отверстия, второй - нет. .map пропускает отверстия.


Используя элемент распространения, массив обрабатывается как итерируемый, т.е. вы получаете итератор для итерации по массиву. Итератор в основном работает как цикл for, он будет перебирать массив из индекса 0 в индекс array.length - 1 (см. спецификацию для подробности) и добавьте значение в каждом индексе к новому массиву. Поскольку ваш массив не содержит никаких значений, array[i] возвращает undefined для каждого индекса.

Это означает, что [...new Array(3)] приводит к массиву, который буквально содержит три значения undefined, а не только "запасной" массив длины 3.

Посмотрите разницу в Chrome:

введите описание изображения здесь

Мы называем "разреженные массивы" также "массивами с дырками".

Вот крут: многие методы массива, включая .map, пропустить дыры! Они не обрабатывают отверстие как значение undefined, полностью игнорируют его.

Вы можете легко убедиться, что, положив console.log в обратный вызов .map:

Array(3).map(() => console.log('call me'));
// no output

Ответ 2

Array

arrayLength

Если единственным аргументом, переданным конструктору Array, является целое число от 0 до 2 32 -1 (включительно), это возвращает новый Массив JavaScript с длиной, установленной для этого числа.

new Array(3) фактически не создает итерируемые значения в созданном массиве, у которого свойство .length установлено на 3.

См. также Undefined значения с новым массивом() в JavaScript.

Вы можете использовать Array.from() в первом примере для возврата ожидаемых результатов

var x = Array.from(Array(3)).map(()=>1);

Оператор распространения

Оператор спрединга позволяет расширять выражение в местах где несколько аргументов (для вызовов функций) или нескольких элементов (для литералов массива) или нескольких переменных (для деструктурирования назначение).

var x = [...new Array(10)].map(()=>1);

создает массив, имеющий значения undefined и .length, установленный в 10 из Array(10), который можно итерализовать в .map()

Ответ 3

Почему случай 1 не работает?

Функция карты вызывает функцию обратного вызова в каждом элементе в порядке возрастания

В вашем первом случае (разбивка..),

var x = new Array(3);
x = x.map( () => 1 );

x - массив с неинициализированным индексом. Поэтому функция map не знает, с чего начать итерацию вашего массива. И заставить его не повторять его вообще (что не работает).

Вы можете проверить его (в Chrome),

var x = new Array(5);
// This will display '[undefined x 5]' in chrome, because their indexes are uninitialized

x[1] = undefined;
// '[undefined x 1, undefined, undefined x 3]' Only array[1] that has its index.
// And you can use 'map' function to change its value.

x = x.map( () => 1 );
// '[undefined x 1, 1, undefined x 3]'

Почему использование этого оператора спрэда делает такую ​​разницу?

В вашем втором примере

Оператор Spread позволяет инициализировать части литерала массива из итерируемого выражения

И заключите его в квадратную скобку, чтобы правильно использовать его.

Итак, [...new Array(2)] на самом деле является индексированным массивом [undefined, undefined].

Так как ваш массив в следующем примере был проиндексирован. Давайте посмотрим (в Chrome),

var x = [...new Array(2)];
// Now 'x' is an array with indexes [undefined, undefined]

x = x.map( () => 1 );
// Will return [1, 1]

Теперь каждое значение в x имеет свои собственные индексы. Затем, наконец, функция map может выполнять итерацию по ней и вызывать функцию обратного вызова для каждого элемента в порядке возрастания.