Подтвердить что ты не робот

Undefined значения в инициализаторе Array (len)

Рассмотрим:

var a = Array(3);
var b = [undefined,undefined,undefined];

Какая причина, по которой a.map и b.map дают разные результаты?

a.map(function(){  return 0;  });  //produces -> [undefined,undefined,undefined]
b.map(function(){  return 0;  });  //produces -> [0,0,0]
4b9b3361

Ответ 1

Конструктор массива создает массив с заданной длиной. Он не создает ключи. Array.prototype.map функция обратного вызова выполняется только для элементов в списке.
То есть все значения, связанные с ключом (целое число) 0 & le; я < длина.

  • Array(3) имеет нулевые ключи, поэтому .map обратный вызов никогда не запускается.
  • [void 0, void 0, void 0] имеет три клавиши, для которых выполнена функция обратного вызова.

    Array(3).hasOwnProperty(0);                 // false
    [void 0, void 0, void 0].hasOwnProperty(0); // true
    

Спецификация и ее polyfill указаны в MDN. На строке 47 if (k in O) { показано, что несуществующие ключи не обрабатываются функцией обратного вызова.

Ответ 2

От MDN:

callback вызывается только для индексов массива, которые назначены значения; он не вызывается для индексов, которые были удалены или которые никогда не были назначены значения.

Для массива a вы создали экземпляр массива длиной 3, но не присвоили никаких значений. Функция карты не находит элементов с назначенными значениями, поэтому не создает новый массив.

Для массива b вы создали экземпляр массива из 3 элементов, каждый со значением undefined. Функция карты находит 3 элемента с назначенными значениями и возвращает "0" в качестве нового значения для каждого из них в новом массиве.

Ответ 3

a - пустой массив, у которого нет элементов, поэтому функция map создает пустой массив без элементов (в каждой спецификации карта производит результаты, только если [[HasProperty]] истинна.) b - это массив три элемента, поэтому карта создает массив из трех элементов.

Ответ 4

map выполняет только итерации существующих свойств, а не пустые индексы.

Поэтому, если вы хотите, чтобы он работал, вы должны сначала заполнить массив.

Существует несколько способов сделать это, например:

  • .fill(), введенный в ES6

    console.log(new Array(3).fill().map(function(){ return 0; }));

Ответ 5

Построенные массивы перечислимы, но пусты

Array(len) создает массив и соответственно устанавливает его длину, но "перечислимой" является только его длина, а не содержащиеся в ней значения. Таким образом, вы не можете отобразить массив Array(100).map(/* nope */) - это еще не "реальный массив", и он на самом деле пуст, несмотря на правильную длину.

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

array не содержит никаких значений; даже undefined

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

Чтобы заполнить массив, вам нужно как-то итерировать его... Например: [...Array(100)] или Array.from(Array(100))

Я предполагаю, что цель этой инициализации состоит в том, чтобы оптимизировать распределение памяти… в массиве на самом деле ничего нет. MDN говорит "пустые объекты arrayLength ", что может вводить в заблуждение, поскольку попытка получить доступ к любому из "пустых элементов" просто возвращает неопределенное значение… Но мы знаем, что они на самом деле не являются undefined так как map не работает, поэтому мы можем подтвердить, что это действительно пустой массив.

Конструктор эквивалент

Этот пример не пытается отразить спецификацию, но вместо этого иллюстрирует, почему array возвращенный из Array еще не может быть повторен

function * (length) {
  const arr = [];
  Object.defineProperty(arr, 'length', { value: length });
  // Equivalent, but invokes assignment trap and mutates array:
  // arr.length = length;
  Object.defineProperty(arr, Symbol.iterator, {
    value() {
      let i = 0;
      return {
        next() {
          return {
            value: undefined, // (Not omitted for illustration)
            done: i++ == length
          };
        }
      }
    }
  })
  return arr;
}

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

Array(len) Спецификация

https://www.ecma-international.org/ecma-262/6.0/#sec-array-len

Array (len) Это описание применяется тогда и только тогда, когда конструктор Array вызывается только с одним аргументом.

1) Пусть numberOfArgs будет количеством аргументов, переданных этому вызову функции.

2) numberOfArgs: numberOfArgs= 1.

3) Если NewTarget не undefined, пусть newTarget будет активным функциональным объектом, иначе пусть newTarget будет NewTarget.

4) Пусть proto будет GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%").

5) ReturnIfAbrupt(proto).

6) Пусть массив будет ArrayCreate(0, proto).

7) Если Type (len) не является Number, то

а) Пусть defineStatus будет CreateDataProperty(array, "0", len).

б) defineStatus: defineStatus имеет значение true.

в) Пусть intLen будет 1.

8) intLen, а) Пусть intLen будет ToUint32 (len). б) Если intLenlen, бросить исключение RangeError.

9) Пусть setStatus будет установлен (массив, "длина", intLen, true).

10) setStatus: setStatus не является внезапным завершением.

11) Возвращаем массив.