Почему мне нужно скопировать массив, чтобы использовать метод для него?
Я могу использовать Array()
чтобы получить массив с фиксированным числом неопределенных записей. Например
Array(2); // [empty × 2]
Но если я пойду и использую метод map, скажем, в моем новом массиве, записи все еще не определены:
Array(2).map( () => "foo"); // [empty × 2]
Если я скопирую массив, карта работает:
[...Array(2)].map( () => "foo"); // ["foo", "foo"]
Зачем мне нужна копия для использования массива?
Ответы
Ответ 1
При использовании Array(arrayLength)
, чтобы создать массив, вы будете иметь:
новый массив JavaScript со свойством length, установленным на это число (Примечание: это подразумевает массив пустых слотов arrayLength, а не слотов с фактическими неопределенными значениями).
Массив на самом деле не содержит никаких значений, даже не undefined
значений - он просто имеет свойство length
.
Когда вы распространяете элемент со свойством length
в массив, например [...{ length: 4 }]
, синтаксис распространения получает доступ к каждому индексу и устанавливает значение этого индекса в новом массиве. Например:
const arr1 = [];
arr1.length = 4;
// arr1 does not actually have any index properties:
console.log('1' in arr1);
const arr2 = [...arr1];
console.log(arr2);
console.log('2' in arr2);
Ответ 2
Причина в том, что элемент массива не назначен. Смотрите здесь первый абзац описания.... обратный вызов вызывается только для индексов массива, которым присвоены значения, в том числе неопределенные.
Рассматривать:
var array1 = Array(2);
array1[0] = undefined;
// pass a function to map
const map1 = array1.map(x => x * 2);
console.log(array1);
console.log(map1);
Выходы:
Array [undefined, undefined]
Array [NaN, undefined]
Когда массив печатается, каждый из его элементов опрашивается. Первый был назначен undefined
другой по умолчанию undefined
.
Операция отображения вызывает операцию отображения для первого элемента, поскольку она была определена (посредством назначения). Он не вызывает операцию сопоставления для второго аргумента, а просто теряет значение undefined
.
Ответ 3
Как указывает @CertainPerformance, ваш массив не имеет никаких свойств, кроме его length
, вы можете проверить это с помощью следующей строки: new Array(1).hasOwnProperty(0)
, которая возвращает false
.
Посмотрев на 15.4.4.19 Array.prototype.map, вы можете увидеть, на 7.3 есть проверка, существует ли ключ в массиве.
1..6. [...]
7. Повторите, пока k < len
-
Пусть Pk будет ToString (k).
-
Пусть kPresent будет результатом вызова внутреннего метода [[HasProperty]] для O с аргументом Pk.
- Если kPresent верно, то
-
Пусть kValue будет результатом вызова внутреннего метода [[Get]] для O с аргументом Pk.
-
Пусть mappedValue будет результатом вызова внутреннего метода [[Call]] для callbackfn с T в качестве значения this и списком аргументов, содержащим kValue, k и O.
-
Вызвать внутренний метод [[DefineOwnProperty]] объекта A с аргументами Pk, дескриптор свойства {[[Value]]: mappedValue, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true } и ложь.
-
Увеличьте k на 1.
9. Верните А.
Ответ 4
Как уже указывалось, Array(2)
будет создавать только массив из двух пустых слотов, которые не могут быть отображены.
Что касается some
и every
, Array(2)
действительно пустой массив:
Array(2).some(() => 1 > 0); //=> false
Array(2).every(() => 1 < 0); //=> true
Однако этот массив пустых слотов можно каким-то образом "повторить":
[].join(','); //=> ''
Array(2).join(','); //=> ','
JSON.stringify([]) //=> '[]'
JSON.stringify(Array(2)) //=> '[null,null]'
Таким образом, мы можем использовать эти знания, чтобы придумать интересные и несколько ироничные способы использования функций массива ES5 в таких "пустых" массивах.
Вы сами придумали это:
[...Array(2)].map(foo);
Вариант предложения от @charlietfl:
Array(2).fill().map(foo);
Лично я бы порекомендовал это:
Array.from(Array(2)).map(foo);
Немного старая школа:
Array.apply(null, Array(2)).map(foo);
Этот довольно многословный:
Array(2).join(',').split(',').map(foo);