Выделить новый массив в 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
может выполнять итерацию по ней и вызывать функцию обратного вызова для каждого элемента в порядке возрастания.