Разница между 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/...