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

В ES6 итерируемый является объектом, который позволяет for... of и имеет ключ Symbol.iterator.

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

Документация 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 (особенно при последнем сравнении). Любое понимание этого странного поведения здесь также будет оценено.

3 ответа

Решение

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

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

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

Для всех, кто пришел сюда после попытки повторить 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')]

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

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

Добавить Symbol.iterator Поддержка для NodeList во всех браузерах к вашему коду, просто используйте следующий polyfill:

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Другие вопросы по тегам