Разница между Array.apply(null, Array (x)) и Array (x)
В чем же разница между:
Array(3)
// and
Array.apply(null, Array(3) )
Первая возвращает [undefined x 3]
, а вторая возвращает [undefined, undefined, undefined]
. Второе связано с цепью через Array.prototype.functions
, например, .map
, но первое - нет. Почему?
Ответы
Ответ 1
Есть разница, довольно значительная.
Конструктор Array
либо принимает одно единственное число, задавая длину массива, и создается массив с "пустыми" индексами, или, вернее, длина устанавливается, но массив не работает 'действительно содержит что-либо
Array(3); // creates [], with a length of 3
При вызове конструктора массива с номером в качестве единственного аргумента вы создаете массив, который является пустым и не может быть повторен с помощью обычных методов Array.
Или... конструктор Array принимает несколько аргументов, тогда как создается массив, где каждый аргумент является значением в массиве
Array(1,2,3); // creates an array [1,2,3] etc.
Когда вы вызываете это
Array.apply(null, Array(3) )
Это немного интереснее.
apply
принимает значение this
в качестве первого аргумента, и поскольку оно здесь не полезно, оно устанавливается на null
Интересной частью является второй аргумент, в котором передается пустой массив.
Поскольку apply
принимает массив, это будет похоже на вызов
Array(undefined, undefined, undefined);
и создает массив с тремя индексами, которые не пусты, но имеют значение, фактически установленное на undefined
, поэтому он может быть итерирован.
TL; DR
Основное отличие состоит в том, что Array(3)
создает массив с тремя индексами, которые пусты. Фактически, они действительно не существуют, массив имеет длину 3
.
Передача такого массива с пустыми индексами в конструктор Array с использованием apply
совпадает с выполнением Array(undefined, undefined, undefined);
, который создает массив с тремя индексами undefined
, а undefined
на самом деле является значением, поэтому он не пуст, как в первом примере.
Массивные методы, такие как map()
, могут перебирать только действительные значения, а не пустые индексы.
Ответ 2
API .map()
не перебирает полностью неинициализированные элементы массива. Когда вы создаете новый массив с конструктором 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"
Внешний вызов конструктора Array будет явно заполнять элементы.
Ответ 3
Это артефакт того, как применяются работы. Когда вы выполните:
new Array(9)
создается пустой массив с длиной 9. Карта не посещает несуществующие элементы, поэтому ничего не делает. Однако apply превращает массив в список, используя CreateListFromArrayLike, поэтому он превращает прежний пустой массив в список параметров, например:
[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
который передается массиву Array для создания массива с 9 членами, со значением undefined. Итак, теперь карта посетит их всех.
BTW, ECMAScript 2015 имеет Array.prototype.fill для этого (также см. MDN), чтобы вы могли:
Array(9).fill(0);
Ответ 4
Поскольку первый массив не имел упорядоченных свойств arr[0] === undefined
, а второй -. Функции массива, такие как forEach и map, будут перебираться с 0 на длину массива - 1, а проблема отсутствия первого свойства - проблема. Вторая версия создает массив с правильным порядком, т.е.
arr = Array.apply(null, Array(3));
arr[0] === undefined //true
arr[1] === undefined //true
//etc.
Первая версия, как вы заметили, не делает. Кроме того, добавление new
в первую версию не заставит его работать.
Ответ 5
В первом случае у вас есть одна операция
Array (3)
Создает массив с тремя пустыми слотами. Не массив с тремя неопределенными значениями, а точно - пустой.
Во втором случае
Array.apply(null, Array (3))
мы можем распространить его на три операции:
-
первое: Array (3) - вы получаете массив с 3 пустыми слотами;
-
второе: Array (3) распространяется функцией Function.prototype.apply() на 3 параметра, которые он передает функции Array(). На этом этапе 3 пустых слота в данном массиве преобразуются с помощью apply() в 3 неопределенных значения (похоже, если apply() видит пустой слот, автоматически превращает его в неопределенное в любом разбросанном массиве).
-
третье: мы получаем массив (не определено, не определено, не определено). И это сделает нам массив с 3 неопределенными (не пустыми) значениями.
Поскольку теперь у вас есть 3 неопределенных, но не пустых слота, вы можете использовать их с функцией map().
Обратите внимание, что не только Function.prototype.apply() имеет такое поведение разложения массивов таким способом. Вы также можете сделать это в ECMAScript 6 с помощью "..." - оператора распространения.
Array(...new Array(3));
Это также вернет массив с 3 неопределенными и соответственно может быть отображены слоты.
Здесь я дал более подробное объяснение. fooobar.com/info/8949612/...