HTMLCollection 和 NodeList 是可迭代的吗?

IT技术 javascript ecmascript-6 nodelist htmlcollection
2021-03-22 07:54:10

在 ES6 中,一个可迭代对象是一个允许for... of,并且有一个 Symbol.iterator 键的对象。

数组是可迭代的,集合和映射也是。问题是:HTMLCollectionNodeList 是可迭代的吗?他们应该是吗?

MDN 文档似乎暗示 aNodeList是可迭代的。

for...ofloops 将在支持的浏览器中正确循环 NodeList 对象for...of(如 Firefox 13 及更高版本)

这似乎证实了 Firefox 的行为。

我在 Chrome 和 Firefox 中测试了以下代码,并惊讶地发现 Firefox 似乎认为它们是可迭代的,但 Chrome 没有。另外,Firefox 认为HTMLCollection返回的迭代器NodeList是一回事。

var col = document.getElementsByClassName('test'); // Should get HTMLCollection of 2 elems
var nod = document.querySelectorAll('.test');      // Should get NodeList of 2 elems
var arr = [].slice.call(col);                      // Should get Array of 2 elems

console.log(col[Symbol.iterator]);    // Firefox: iterator function, Chrome: undefined
console.log(nod[Symbol.iterator]);    // Firefox: iterator function, Chrome: undefined
console.log(arr[Symbol.iterator]);    // Firefox & Chrome: iterator function
console.log(col[Symbol.iterator] === nod[Symbol.iterator]);  // Firefox: true
console.log(col[Symbol.iterator] === arr[Symbol.iterator]);  // Firefox: false
<div class="test">1</div>
<div class="test">2</div>

一件非常奇怪、令人困惑的事情:运行代码片段会产生与复制它并在 Firefox 中的实际文件/控制台中运行不同的结果(特别是最后的比较)。对这里这种奇怪行为的任何启发也将不胜感激。

4个回答

Symbol.iteratorNodeListHTMLCollectionDOMTokenList和 的支持在去年DOMSettableTokenList讨论添加WHATWG 的 DOM 规范中

好吧,从技术上讲,ES6 和 WHATWG 都不是委员会。TC39 是一个标准化 ECMAScript 的委员会。WHATWG 是一个标准化相关类的社区。TC39 无意标准化这些类。
2021-04-22 07:54:10
从技术上讲,ES6 和 WHATWG 是不同的委员会。ES6 委员会认为 WHATWG 仅仅是 ES5 的起点,并且标准从那时起就从那时起忽略了 WHATWG。仍然有人同时是两个委员会的成员,所以我希望它会在某个时候被推荐给 ES6 委员会(尽管更有可能被推荐给 ES7,因为 ES7 处于草案模式而 ES6 被认为是“最终的” )
2021-05-16 07:54:10

不幸的是,还没有。但是在它们出现之前,您可以像这样轻松地对它们进行 polyfill:

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
是啊,这就是我现在做了什么HTMLCollection NodeList奇怪的是,Chrome/Opera 并不认为它们是可迭代的,而 Firefox 却这样做了。从目前的评论来看,我猜他们应该是,但我不能 100% 确定。
2021-05-21 07:54:10

正如greiner 所指出的那样,2014 年 WHATWG 的 DOM 规范中添加了对本机的Symbol.iterator支持NodeList

不幸的是,Chrome 51 是第一个支持它的 Chrome 版本,在撰写此答案时,它的 Beta 版才刚刚发布。此外,任何版本的 Internet Explorer 或 Edge 都不支持。

在所有浏览器中为您的代码添加Symbol.iterator支持NodeList,只需使用以下 polyfill :

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

对于尝试使用 TypeScript 迭代 NodeList 到达这里的任何人。我通过修复https://github.com/microsoft/TypeScript/issues/4947发现了这个问题,这是tsconfig.json您需要的:

{
  "compilerOptions": {
    "lib": ["es2017", "dom", "dom.iterable"],
    "downlevelIteration": true
  }
}

我得到的问题错误:

Type 'NodeListOf<Element>' is not an array type.

这是触发该问题的代码:

[...document.querySelectorAll('#md-view a')]