Являются ли HTMLCollection и NodeList итерируемыми?

В ES6 iterable — это объект, который допускает for... of и имеет Symbol.iterator ключ.

Массивы являются итерируемыми, как и множества и карты. Вопрос в том, являются ли HTMLCollection и NodeList iterables? Они должны быть?

Документация MDN, кажется, предполагает, что NodeList является итерируемым.

Циклы for...of будут корректно перебирать объекты NodeList в браузерах, поддерживающих for...of (например, Firefox 13 и более поздние версии).

Похоже, это подтверждает поведение Firefox.

Я протестировал следующий код как в Chrome, так и в Firefox и был удивлен, обнаружив, что Firefox, похоже, считает их итерируемыми, а Chrome — нет. Кроме того, Firefox считает, что итераторы, возвращаемые HTMLCollection и NodeList, являются одними и теми же.

var col = document.getElementsByClassName('test'); // Should get HTMLCollection of 2 elems
var nod = document.querySelectorAll('.test');      // Should get NodeList of 2 elems
var arr = [].slice.call(col);                      // Should get Array of 2 elems

console.log(col[Symbol.iterator]);    // Firefox: iterator function, Chrome: undefined
console.log(nod[Symbol.iterator]);    // Firefox: iterator function, Chrome: undefined
console.log(arr[Symbol.iterator]);    // Firefox & Chrome: iterator function
console.log(col[Symbol.iterator] === nod[Symbol.iterator]);  // Firefox: true
console.log(col[Symbol.iterator] === arr[Symbol.iterator]);  // Firefox: false
<div class="test">1</div>
<div class="test">2</div>

Одна действительно странная и запутанная вещь: запуск фрагмента кода дает результат, отличный от его копирования и запуска в реальном файле/консоли в Firefox (особенно последнее сравнение). Любое просвещение по этому странному поведению здесь тоже будет оценено.


person light    schedule 08.07.2015    source источник
comment
Это не итерация в Chrome, но она должна быть. См. раздел ошибка 401699: добавление поддержки итератора в NodeList и друзьям.   -  person lyschoening    schedule 08.07.2015
comment
Вы можете проверить NodeList.js   -  person Edwin Reynoso    schedule 08.08.2015
comment
Это также не итерация в Safari.   -  person Barmar    schedule 30.12.2016


Ответы (4)


Symbol.iterator поддержка NodeList, HTMLCollection, DOMTokenList и DOMSettableTokenList была обсуждена и добавлены в раздел спецификация DOM WHATWG в прошлом году.

person greiner    schedule 22.07.2015
comment
С технической точки зрения ES6 и WHATWG — это разные комитеты. Комитет ES6 рассматривает WHATWG просто как отправную точку ES5, и отсюда развиваются стандарты, игнорируя WHATWG с этого момента. Тем не менее есть люди, которые являются членами обоих комитетов, поэтому я ожидаю, что в какой-то момент это будет предложено комитету ES6 (хотя, скорее всего, это будет предложено ES7, поскольку ES7 находится в черновом режиме, а ES6 считается окончательным) - person slebetman; 23.07.2015
comment
Ну, с технической точки зрения ни ES6, ни WHATWG не являются комитетом. TC39 — это комитет, который стандартизирует ECMAScript. А WHATWG — это сообщество, которое стандартизирует рассматриваемые классы. TC39 не стремится стандартизировать эти классы. - person Anne; 10.09.2015

К сожалению, пока нет. Но до тех пор, пока они не появятся, вы можете легко заполнить их так:

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
person Jwashton    schedule 13.08.2015
comment
Да, это именно то, что я сейчас делаю для HTMLCollection и NodeList. Просто странно, что Chrome/Opera не считает их итерируемыми, в то время как Firefox это делает. Судя по комментариям, они должны быть, но я не могу быть уверен на 100%. - person light; 14.08.2015

Как указал greiner, в 2014 году в спецификацию DOM WHATWG была добавлена ​​встроенная поддержка Symbol.iterator для NodeList. .

К сожалению, Chrome 51 — первая версия Chrome, поддерживающая его, и на момент написания этого ответа его бета-версия была выпущена только что. Кроме того, нет поддержки ни в одной версии Internet Explorer или Edge.

Чтобы добавить в код Symbol.iterator поддержку NodeList во всех браузерах, просто используйте следующий полифилл:

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
person John Slegers    schedule 29.04.2016

Для всех, кто прибывает сюда после попытки повторения NodeList с использованием TypeScript. Я нашел эту проблему с исправлением https://github.com/microsoft/TypeScript/issues/4947 и это tsconfig.json вам понадобится для этого:

{
  "compilerOptions": {
    "lib": ["es2017", "dom", "dom.iterable"],
    "downlevelIteration": true
  }
}

Ошибка проблемы, которую я получал:

Type 'NodeListOf<Element>' is not an array type.

И это был код, который вызывал эту проблему:

[...document.querySelectorAll('#md-view a')]
person ubershmekel    schedule 02.06.2020