【问题标题】:Can HTMLCollections be iterated with for...of (Symbol.iterator)?可以用 for...of (Symbol.iterator) 迭代 HTMLCollections 吗?
【发布时间】:2017-06-05 04:00:16
【问题描述】:

DOM4 使 NodeLists 可迭代:

interface NodeList {
  getter @987654322@? @987654323@(unsigned long index);
  readonly attribute unsigned long @987654324@;
  iterable<@987654325@>;
};

根据WebIDL,这意味着

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

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

所以以下是可能的:

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

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

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

其实我明白了

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

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

interface HTMLCollection {
  readonly attribute unsigned long @987654330@;
  getter @987654331@? @987654332@(unsigned long index);
  getter @987654333@? @987654334@(DOMString name);
};

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

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

【问题讨论】:

标签: javascript dom language-lawyer iterable htmlcollection


【解决方案1】:

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

如果interface 有以下任何一项:

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

如果接口定义了indexed property getter,那么 函数对象是%ArrayProto_values%

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

getter @987654333@? @987654334@(unsigned long <i>index</i>);

还有一个名为“length”的整数类型属性:

readonly attribute unsigned long @987654335@;

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

【讨论】:

  • 我要这是因为HTMLCollection 上的namedItem 方法或声明“注意:元素是表示集合的更好解决方案元素。HTMLCollection 是我们无法摆脱网络的历史产物。”
  • @lonesomeday 是的,看起来是这样,因为namedItem 接受一个字符串,添加像forEach 这样的属性可能会破坏事情。
【解决方案2】:

在 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

【讨论】:

  • 谢谢,我已经知道@@iterator,我担心HTMLCollection 是否应该返回一个合适的迭代器
  • @Oriol 我认为这取决于实现。 HTMLCollection 接口没有声明迭代器,但实现时您也可以包含另一个接口。在这种情况下,HTMLCollection 和 NodeList 是集合的表示,它们确实是可迭代的。
猜你喜欢
  • 2018-09-06
  • 1970-01-01
  • 2020-10-09
  • 2018-09-04
  • 2020-06-27
  • 2017-02-08
  • 1970-01-01
  • 2021-10-21
相关资源
最近更新 更多