Are HTMLCollection and NodeList iterables?
Asked Answered
B

4

26

In ES6, an iterable is an object that allows for... of, and has a Symbol.iterator key.

Arrays are iterables, as are Sets and Maps. The question is: are HTMLCollection and NodeList iterables? Are they supposed to be?

MDN documentation seems to suggest a NodeList is an iterable.

for...of loops will loop over NodeList objects correctly, in browsers that support for...of (like Firefox 13 and later)

This appears to corroborate Firefox's behaviour.

I tested the following code in both Chrome and Firefox, and was surprised to find that Firefox seem to think they are iterables, but Chrome does not. In addition, Firefox thinks that the iterators returned by HTMLCollection and NodeList are one and the same.

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>

One really weird, confusing thing: running the code snippet produces a different result from copying it and running in an actual file/console in Firefox (particularly last comparison). Any enlightenment on this weird behaviour here would be appreciated too.

Beatabeaten answered 8/7, 2015 at 4:9 Comment(3)
It is not an iterable in Chrome, but it is supposed to be. See Issue 401699: Add iterator support to NodeList and friendsPenultimate
You may want to check out NodeList.jsAusterlitz
It's not an iterable in Safari, either.Sherylsheryle
C
9

Symbol.iterator support for NodeList, HTMLCollection, DOMTokenList, and DOMSettableTokenList was discussed and added to the WHATWG's DOM spec last year.

Cotemporary answered 22/7, 2015 at 22:11 Comment(2)
Technically speaking, ES6 and WHATWG are different committees. The ES6 committee considers WHATWG as merely the starting point of ES5 and standards evolve from there on ignoring WHATWG from that point onwards. Still there are people who are members of both committees so I'd expect that it would be suggested to the ES6 committee at some point (though it's more likely to be suggested to ES7 since ES7 is in draft mode while ES6 is considered "final")Starry
Well, technically speaking neither ES6 nor WHATWG is a committee. TC39 is a committee that standardizes ECMAScript. And WHATWG is a community that standardizes the classes in question. TC39 has no ambition to standardize these classes.Microbicide
O
6

Unfortunately, not yet. But until they are, you can easily polyfill them like so:

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Orly answered 13/8, 2015 at 21:57 Comment(1)
Yup, that's exactly what I'm doing now for HTMLCollection and NodeList. It's just strange that Chrome/Opera doesn't consider them iterables while Firefox does. From the comments so far, I guess they are supposed to be, but I can't be 100% sure.Beatabeaten
C
3

For anyone arriving here from trying to iterate on NodeList using TypeScript. I found this issue with the fix https://github.com/microsoft/TypeScript/issues/4947 and this is the tsconfig.json you'll need for it:

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

The problem error I was getting:

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

And this was the code that was triggering that problem:

[...document.querySelectorAll('#md-view a')]
Capacitor answered 2/6, 2020 at 23:7 Comment(0)
R
2

As greiner pointed out, native Symbol.iterator support for NodeList was added to the WHATWG's DOM spec in 2014.

Unfortunately, Chrome 51 is the first version of Chrome to support it, and its Beta has only just been released at the time of writing this answer. Also, there's no support in any version of Internet Explorer or Edge.

To add Symbol.iterator support for NodeList in all browsers to your code, just use the following polyfill :

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Ratcliffe answered 29/4, 2016 at 22:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.