Разница между массивом.применить (null, Array (x)) и Array (x)

в чем именно разница между:

Array(3)
// and
Array.apply(null, Array(3) )

первый возвращает [undefined x 3] в то время как второй возвращает [undefined, undefined, undefined]. Второй-цепной через Array.prototype.functions например .map, но первый-нет. Почему?

4 ответов


есть разница, довольно существенная.

на Array конструктор или принимает одно единственное число, давая длину массива, и создается массив с "пустыми" индексами, или, правильнее, длина устанавливается, но массив на самом деле ничего не содержит

Array(3); // creates [], with a length of 3

при вызове конструктора массива с номером в качестве единственного аргумента вы создаете массив, который пуст, и который не может быть повторен с обычными методами массива.

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

Array(1,2,3); // creates an array [1,2,3] etc.

когда вы называете это

Array.apply(null, Array(3) )

это становится немного интереснее.

apply принимает this значение в качестве первого аргумента, и как это не полезно, это null

интересная часть второй аргумент, в котором передается пустой массив.
As apply принимает массив, это было бы похоже на вызов

Array(undefined, undefined, undefined);

и это создает массив с тремя индексами, который не пуст, но имеет значение, фактически установленное в undefined, поэтому его можно повторить.

TL; DR
Главное отличие в том, что Array(3) создает массив с тремя пустыми индексами. На самом деле, они на самом деле не существуют, массив просто имеет длина 3.

передача такого массива с пустыми индексами конструктору массива с помощью apply это то же самое, что делать Array(undefined, undefined, undefined);, который создает массив с тремя undefined индексы, и undefined фактически является значением, поэтому он не пуст, как в первом примере.

методы, такие как map() можно только перебирать фактические значения, а не пустые индексы.


на .map() API не выполняет итерацию по полностью неинициализированным элементам массива. Когда вы создаете новый массив с помощью new Array(n) конструктор, вы получаете массив с .length вы просили, но с несуществующими элементами, которые будут пропущены методы, такие как .map().

выражение Array.apply(null, Array(9)) явно заполняет вновь созданный экземпляр массива undefined, но этого достаточно. Фокус в том, является ли in оператор сообщит, что массив содержит элемент по заданному индексу. То есть:

var a = new Array(9);
alert(2 in a); // alerts "false"

это потому, что на самом деле нет элемента в позиции 2 в массиве. Но:

var a = Array.apply(null, Array(9));
alert(2 in a); // alerts "true"

внешний вызов конструктора массива будет явно заполнен элементами.


это артефакт того, как применить строительство. Когда вы делаете:

new Array(9)

создается пустой массив длиной 9. карта не посещает несуществующих членов, поэтому ничего не делает. Однако,применить превращает массив в список с помощью CreateListFromArrayLike таким образом, он превращает ранее пустой массив в список параметров, например:

[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];

это передается массив чтобы создать массив с 9 членами, все со значением неопределено. Так что теперь карта посетит их всех.

кстати, ECMAScript 2015 имеет массив.прототип.заполнить для этого (см. Также MDN) так что вы можете сделать:

Array(9).fill(0);

потому что первый массив не будет иметь упорядоченных свойств arr[0] === undefined и второй делает. Функции массива, такие как forEach и map, будут повторяться от 0 до длины массива - 1, и отсутствие порядка для свойств первого является проблемой. Вторая версия создает массив с правильным порядком, т. е.

arr = Array.apply(null, Array(3));
arr[0] === undefined //true
arr[1] === undefined //true
//etc.

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