Undefined значения с новым массивом() в JavaScript

Посмотрев на код javascript, я увидел (что-то вроде этого):

var arr = Array.apply(null, {length: 10});

Чтение документации MDN для функции .prototype.apply(), я узнал, что, хотя обычно он ожидает, что массив является вторым аргументом, который представляет собой массив аргументов, которые должны быть переданы вызываемой функции,

вы также можете использовать любой объект, похожий на массив, поэтому на практике это означает, что он будет иметь длину свойства и целочисленные свойства в диапазоне (0... length).

Итак, из того, что я мог сказать, он вызывал Array(), как будто ему было передано 10 аргументов, но поскольку он не определяет ни одно из этих "целочисленных свойств", он как будто он был передан 10 undefined аргументов. Правильно ли это?

console.log(arr);

дает

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

Что совершенно отличается от результата

var barr = new Array(10);
console.log(barr);

который

[,,,,,]

Эти массивы также ведут себя по-другому.

console.log(arr.map(function(item) { return 'hi';}));
console.log(barr.map(function(item) { return 'hi';}));

дает

['hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi']

[,,,,,]

Я хотел знать, почему функция карты не работает для второй. Поэтому я проверил console.log(1 in arr);, который дал true, и `console.log(1 в barr); ' который дал false.

Итак, моя текущая догадка заключается в том, что arr - это массив, который содержит в качестве целочисленных свойств 10 переменных, каждое из которых имеет значение undefined, а barr - массив, который, хотя он имеет длину 10, не имеет целочисленных свойств. И Array.apply работает, потому что запрашивает {length: 10}, что его свойство 0, получает undefined, и поэтому присваивает undefined свойству 0 массива, которое он строит, и так далее. Правильно ли я рассуждаю? И действительно ли не менее хакерский способ определить массив, содержащий undefined целочисленные свойства для каждого индекса в пределах его диапазона, вместо того, чтобы вообще не иметь целочисленных свойств? Поскольку, глядя на это, мне кажется, что new Array() довольно бесполезен.

Ответ 1

Итак, из того, что я мог сказать, он вызывал Array(), как будто ему было передано 10 аргументов, но поскольку он не определяет ни одно из этих "целочисленных свойств", он как будто он был передан 10 undefined аргументов. Это правильно?

Да, точно. Он делает это:

var arr = Array(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
var barr = new Array(10);
console.log(barr);

...

console.log(arr.map(function(item) { return 'hi';}));
console.log(barr.map(function(item) { return 'hi';}));

Я хотел знать, почему функция карты не работает для второго.

Потому что map, forEach и аналогичные только свойства посещения фактически существуют. Как вы сказали, между ними большая разница.

var arr = Array(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
// Or `var arr = Array.apply(null, {length: 10});

и

var barr = new Array(10);

В первом примере arr имеет 10 записей, каждое из которых имеет значение undefined. Во втором примере barr имеет без записей и length 10. Таким образом, в первом, map будет посещать свойства, потому что они существуют. Во втором, это не будет, потому что они этого не делают.

Напомним, что стандартные массивы в JavaScript на самом деле не являются массивами (раскрытие: это сообщение в моем блоге), они объекты с некоторым особым поведением. Таким образом, они по своей сути являются скудными:

var a = [];
a.length = 10000;

a не имеет 10 000 записей. У него нет записей. Просто это свойство length 10000.

Вы можете определить, существует ли свойство с помощью hasOwnProperty или in. Для сравнения:

var barr = new Array(10);
console.log(barr.hasOwnProperty(0)); // false
console.log(0 in barr);              // false

в

var arr = Array.apply(null, {length: 10});
console.log(arr.hasOwnProperty(0));  // true
console.log(0 in arr);               // true

И Array.apply работает, потому что запрашивает {length: 10} то, что имеет его свойство 0, получает undefined и поэтому присваивает undefined свойству 0 построенного массива и т.д. Правильны ли мои рассуждения?

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

И действительно ли не менее хакерский способ определить массив, содержащий undefined целочисленные свойства для каждого индекса в пределах его диапазона, вместо того, чтобы вообще не иметь целочисленных свойств?

Только незначительно: ES2015 добавляет Array.from, который принимает объект, подобный массиву, и возвращает истинный массив (необязательно сопоставляя записи). Итак, это будет:

var arr = Array.from({length:10});

Редко нужно делать это, а не просто a = new Array(bigNumberHere); или a = []; a.length = bigNumberHere. Например, много раз вам все равно, существует ли свойство или существует со значением undefined. Иногда вы это делаете, но, чтобы дать вам перспективу, я профессионально писал JavaScript в течение 20 лет, довольно интенсивно, последние 8, и мне, вероятно, было интересно, о, один или два раза, вершины.

Вы упомянули, что в конкретном случае, с которым вы имели дело, он был объединен с map, поэтому Array.from займет место обоих:

var arr = Array.from({length: 10}, function() { return "hi"; });

... дает

["hi", "hi", "hi", "hi", "hi", "hi", "hi", "hi", "hi", "hi"]

Хотя Array.from является новым в ES2015, он может быть зачищен/полилизован на старых машинах JavaScript.

Ответ 2

Правильно ли это?

Да

вы также можете использовать любой объект, похожий на массив, поэтому в практика означает, что он будет иметь длину свойства и целое число свойства в диапазоне (0... длина).

В нем говорится, что вы можете передать утиный тип массива: объект, который имеет своего рода интерфейс:

  • свойство length (для итерации)
  • необязательный: некоторые целочисленные свойства (значения)

Это будет рассматриваться как массив. Таким образом, передача {length: 10} аналогична передаче реального массива [undefined, undefined, undefined,..] где каждый индекс создан и имеет значение undefined.

Итак, первая строка кода:

var arr = Array.apply(null, {length: 10});

интерпретируется как:

var arr = Array(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined)

Итак, моя текущая догадка заключается в том, что arr является массивом, который содержит целое число свойства 10 переменных, каждая из которых имеет значение undefined и barr - массив, который, хотя он имеет длину 10, не имеет целого числа свойства.

Да.

var test = Array(10);

он выводит: [ undefined x10] < - без индексов, только простое свойство "длина", не привязанное к реальному контенту, но полезно для его получения и выполнения некоторых размерных коннекций.

test[2] = undefined;

выводит: [undefined x2, undefined, undefined x7] < - нет индексов, кроме позиции '2', которая имеет значение: undefined.