Can HTMLCollections be repeated for ... from (Symbol.iterator)?

DOM4 makes NodeList iterable:

interface NodeList { getter Node ? item (unsigned long index ); readonly attribute unsigned long length ; iterable< Node >; }; 

According to WebIDL , this means

Objects that implement an interface declared as iterable support are repeated to obtain a sequence of values.

Note. The ECMAScript language binding uses an interface that iterable will have "entries", "forEach", "keys", "values" and @@ iterator properties on its interface prototype object .

Thus, the following is possible:

 for (var el of document.querySelectorAll(selector)) ... 

I noticed that the same is similar to 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, an 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 specification , and it did not become iterable either.

Then is this standard behavior or not? HTMLCollection have @@iterator in prototype?

+5
source share
2 answers

I found it, he explained in WebIDL :

If interface has one of the following values:

then there must be a property whose name is the @@ iterator symbol, with the attributes {[[Writable]]: true , [[Enumerable]]: false , [[Configurable]]: true } and the value of which the function is an object . [...]

If the interface defines an indexed attribute of a property , then the Function is % ArrayProto_values% .

In this case, the HTMLCollections have an indexed getter property:

 getter Element ? item (unsigned long index ); 

and an integer attribute named "length":

 readonly attribute unsigned long length ; 

So yes, it should work. In fact, it would also work for NodeLists, even if they were not declared as iterable, but then they would not have the properties entries , forEach , keys and values . As @lonesomeday mentions, it is likely that the HTMLCollection is not defined as iterative, because adding these methods will not be backward compatible because gett namedItem accepts arbitrary strings.

+4
source

In JavaScript, almost everything that has an iterable structure can go through some operations of the iteration engine, such as: for..of and ...spread

Any iterable if it returns an iterator for [[Get]] operations against the property in which it stores the @@iterator character, which in this case, apparently, an HTMLCollection returns such an object.

An iterator is considered on its own if it has: next() {method}: and two other optional methods, which are

 return() {method}: stops iterator and returns IteratorResult throw() {method}: signals error and returns IteratorResult 

This is an example of a complete user object that is iterable.

  const calculations = { counting: 1, [Symbol.iterator]: function(){ return this; }, next: function(){ if(this.counting <= 3){ return { value: this.counting++, done: false } } return { value: this.counting, done: true} } }; const data = ...calculations; // [1,2,3] 

So, in your case, as long as the HTMLCollection returns the correct iterator, you can apply for..of and ...spread , but if you for..of to this, it meets the specification than I have to tell you that I do not have a bachelor's degree in computer science : P

0
source

Source: https://habr.com/ru/post/1263087/


All Articles