DOM4 makes NodeLists iterable:
interface NodeList {
getter Node? item(unsigned long index);
readonly attribute unsigned long length;
iterable<Node>;
};
According to WebIDL, this means
Objects implementing an interface that is declared to be iterable support being iterated over to obtain a sequence of values.
Note: In the ECMAScript language binding, an interface that is iterable will have “entries”, “forEach”, “keys”, “values” and @@iterator properties on its interface prototype object.
So the following is possible:
for (var el of document.querySelectorAll(selector)) ...
I noticed the same seems to work for HTMLCollections, both on Firefox and Chrome:
for (var el of document.getElementsByTagName(tag)) ...
In fact, I get
HTMLCollection.prototype[Symbol.iterator] === [][Symbol.iterator]; // true
However, HTMLCollection is not defined as iterable:
interface HTMLCollection {
readonly attribute unsigned long length;
getter Element? item(unsigned long index);
getter Element? namedItem(DOMString name);
};
I also checked the WHATWG DOM spec and it's not iterable neither.
Then, is this behavior standard or not? Is HTMLCollection
supposed to have an @@iterator
in the prototype?
Description. Whenever an object needs to be iterated (such as at the beginning of a for...of loop), its @@iterator method is called with no arguments, and the returned iterator is used to obtain the values to be iterated. Some built-in types have a default iteration behavior, while other types (such as Object ) do not.
NodeList and DOMTokenList should have [Symbol. iterator] because they're iterable.
The length() Property is used to return the collection of all HTML elements in a document. It is read-only property and is quite useful when a user wants to loop through an HTML Collection. Return Value: It returns a number which represent the number of all elements in a HTML Collection.
I found it, it's explained in WebIDL:
If the interface has any of the following:
- an iterable declaration
- an indexed property getter and an integer-typed attribute named “length”
- a maplike declaration
- a setlike declaration
then a property must exist whose name is the @@iterator symbol, with attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } and whose value is a function object. [...]
If the interface defines an indexed property getter, then the Function object is %ArrayProto_values%.
In this case, HTMLCollections have an indexed property getter:
getter Element? item(unsigned long index);
and an integer-typed attribute named “length”:
readonly attribute unsigned long length;
Therefore, yes, it's supposed to work. In fact, it would also work for NodeLists even if they weren't declared as iterable, but then they wouldn't have the entries
, forEach
, keys
and values
properties. As @lonesomeday mentions, it's probable that HTMLCollection is not defined as iterable because adding these methods wouldn't be backwards-compatible, due to the fact that the namedItem
getter accepts arbitrary strings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With