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

Ori*_*iol 7 javascript dom iterable language-lawyer htmlcollection

DOM4使NodeList可迭代:

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

根据WebIDL,这意味着

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

注意:在ECMAScript语言绑定中,可迭代的接口将在其接口原型对象上具有"entries","forEach","keys","values"和 @@ iterator属性.

所以以下是可能的:

for (var el of document.querySelectorAll(selector)) ...
Run Code Online (Sandbox Code Playgroud)

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

for (var el of document.getElementsByTagName(tag)) ...
Run Code Online (Sandbox Code Playgroud)

事实上,我得到了

HTMLCollection.prototype[Symbol.iterator] === [][Symbol.iterator]; // true
Run Code Online (Sandbox Code Playgroud)

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

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

我还检查了WHATWG DOM规范,它也不能迭代.

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

Ori*_*iol 5

我找到了,这在WebIDL中有解释:

如果接口有任何以下内容:

那么必须存在一个名称为@@ iterator符号的属性,其属性为{[[Writable]]:true,[[Enumerable]]:false,[[Configurable]]:true },其值是一个函数对象。[...]

如果接口定义了索引属性getter,则 Function对象为%ArrayProto_values%。

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

getter Element? item(unsigned long index);
Run Code Online (Sandbox Code Playgroud)

以及一个名为“ length”的整数类型的属性:

readonly attribute unsigned long length;
Run Code Online (Sandbox Code Playgroud)

因此,是的,它应该可以工作。事实上,它也将用于的NodeLists工作,即使他们没有申报为迭代,但他们不会有entries,forEach,keys和values属性。正如@lonesomeday提到的那样,很可能HTMLCollection没有被定义为可迭代的,因为添加这些方法将不会向后兼容,因为namedItemgetter可以接受任意字符串。

  • @lonesomeday是的,似乎是这样,因为`namedItem`接受一个字符串,所以添加诸如`forEach`之类的属性可能会破坏事情。 (2认同)