Почему for-of не пропускает пустые слоты разреженного массива?[JavaScript] - PullRequest
0 голосов
/ 28 апреля 2019

Как видно из заголовка, почему for-of запускает тело цикла с переменной цикла , связанной с undefined для индексов, не входящих в Array, тогда как другие конструкции итерации (forEach(), for-in и т. Д.) Не?

Разъяснение : Как многие неправильно поняли вопрос

Это , а не о:

  • итерация по TypedArray с (что не может быть разреженным) или любой другой класс
  • как "правильно" повторить через разреженный Array (кажется, что любой другой метод работает ожидаемым образом)
  • пропуск undefined элементов в Array

Неправильно ли следующее неофициальное описание в MDN ?

Оператор for...of [...] вызывает пользовательский итерационный хук с инструкциями, которые должны выполняться для значения каждого отдельного свойства объекта.

т.е. он также вызывается для несуществующих свойств.

const sparse = [0, 1, 2] // Was [0, , 2], but some are unfamiliar with this syntax 
                         // or think it creates the array [0, undefined, 2]
delete sparse[1]
for (let e of sparse) console.log('for-of', e)
// Contrast with:
sparse.forEach(e => console.log('forEach', e))
for (let i in sparse) console.log('for-in', sparse[i])
console.log('map', sparse.map(e => e)) // Note, prints incorrectly in the snippet
                                       // console, check browser console
// etc.

Это предполагаемое поведение ( Да ) и почему оно было разработано таким образом?

1 Ответ

1 голос
/ 28 апреля 2019

for..of вызывает метод итератора Array, который описан в спецификации .

(2) Пусть итератор будет ObjectCreate (% ArrayIteratorPrototype%, «‍ [[IteratedObject]], [[ArrayIteratorNextIndex]], [[ArrayIterationKind]]»).

(4) Установить внутренний слот итератора [[ArrayIteratorNextIndex]] на 0.

Затем, когда итератор повторяется, в 22.1.5.2.1% ArrayIteratorPrototype% .next: :

(6) Пусть index будет значением внутреннего слота [[ArrayIteratorNextIndex]] для O.

(10) Если индекс ≥ len, то

(10) (a) Установите значение внутреннего слота [[IteratedObject]] для O в значение undefined.

(10) (b) Возвращает CreateIterResultObject (undefined, true).

(11) Установите значение внутреннего слота [[ArrayIteratorNextIndex]] для O в index + 1 .

(создать объект результата итератора со значением array[index])

Другими словами - итератор выполняет итерацию, начиная с индекса 0, и увеличивает индекс на 1 каждый раз, когда вызывается .next(). Он не проверяет, действительно ли массив имеет элемент с этим индексом (чего не будет у разреженного массива) - он просто проверяет, что индекс меньше .length массива.

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

const sparse = [0, , 2];
console.log(sparse.hasOwnProperty('0'));
console.log(sparse.hasOwnProperty('1'));

Так что да, это предполагаемое поведение.

...