可以用(Symbol.iterator)for ...迭代HTMLCollections吗?

时间:2017-01-20 08:18:09

标签: javascript dom language-lawyer iterable htmlcollection

DOM4使NodeList可迭代:

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

根据WebIDL,这意味着

  

实现声明为可迭代的接口的对象   支持迭代以获得一系列值。

     

注意:在ECMAScript语言绑定中,是一个接口   iterable将具有“entries”,“forEach”,“keys”,“values”和   @@iterator上的interface prototype object属性。

以下是可能的:

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

我注意到同样适用于Firefox和Chrome的HTMLCollections:

for (var el of document.getElementsByTagName(tag)) ...

事实上,我得到了

HTMLCollection.prototype[Symbol.iterator] === [][Symbol.iterator]; // true

但是,HTMLCollection未定义为可迭代:

interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

我还检查了WHATWG DOM spec,但它也不可迭代。

那么,这种行为标准与否? HTMLCollection原型中应该有@@iterator吗?

2 个答案:

答案 0 :(得分:5)

我找到了它,它在WebIDL中解释了:

  

如果interface具有以下任何内容:

           

然后必须存在名称为@@iterator符号的属性,   属性{[[Writable]]: true ,[[Enumerable]]: false ,   [[Configurable]]: true },其值为function object。 [...]

     

如果界面定义了indexed property getter,那么   功能对象为%ArrayProto_values%

在这种情况下,HTMLCollections具有索引属性getter:

getter Element? item(unsigned long index);

和名为“length”的整数类型属性:

readonly attribute unsigned long length;

因此,是的,它应该起作用。事实上,它也适用于NodeLists,即使它们没有被声明为可迭代,但它们也不会有entriesforEachkeys和{ {1}}属性。正如@lonesomeday所提到的,HTMLCollection可能未被定义为可迭代,因为添加这些方法不会向后兼容,因为values getter接受任意字符串。

答案 1 :(得分:0)

在JavaScript中,几乎所有具有iterable结构的东西都可以通过一些迭代引擎操作,例如:for..of...spread

如果它返回一个[[Get]]操作的迭代器,对它存储@@iterator符号的属性返回一个迭代器,那么显然HTMLCollection会返回这样一个对象。

如果迭代器具有:next() {method}:,并且还有其他两个可选方法

,则它本身会被计算在内。
return() {method}: stops iterator and returns IteratorResult
throw() {method}: signals error and returns IteratorResult

这是一个可迭代的完整自定义对象的示例。

    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]

因此,在您的情况下,只要HTMLCollection返回正确的迭代器,您就可以应用for..of...spread,但是如果您关注的是它符合规范,那么我必须告诉它你还没有计算机科学学士学位:P