为什么 nodelist 没有 forEach?

IT技术 javascript arrays dom foreach
2021-02-06 14:10:03

我正在编写一个简短的脚本来更改<abbr>元素的内部文本,但发现它nodelist没有forEach方法。我知道这nodelist不是继承自Array,但它似乎不是forEach一个有用的方法吗?是否有我不知道的特定实现问题会阻止添加forEachnodelist

注意:我知道 Dojo 和 jQuery 都有forEach某种形式的节点列表。由于限制,我不能使用。

6个回答

NodeList 现在在所有主要浏览器中都有 forEach()

请参阅MDN 上的 nodeList forEach()

原答案

这些答案都没有解释为什么NodeList 不从 Array 继承,从而允许它拥有forEach和所有其他的。

答案可在此 es-discuss thread 上找到简而言之,它打破了网络:

问题是代码错误地假定 instanceof 意味着该实例是一个与 Array.prototype.concat 结合的数组。

Google 的 Closure Library 中存在一个错误,导致几乎所有 Google 的应用程序都因此而失败。该库在发现后立即更新,但可能仍然存在与 concat 结合使用相同错误假设的代码。

也就是说,一些代码做了类似的事情

if (x instanceof Array) {
  otherArray.concat(x);
} else {
  doSomethingElseWith(x);
}

但是,concat将“真实”数组(不是 instanceof Array)与其他对象区别对待:

[1, 2, 3].concat([4, 5, 6]) // [1, 2, 3, 4, 5, 6]
[1, 2, 3].concat(4) // [1, 2, 3, 4]

所以这意味着上面的代码在x是 NodeList时中断了,因为在它沿着doSomethingElseWith(x)路径走之前,而之后它沿着otherArray.concat(x)路径走,这做了一些奇怪的事情,因为x它不是一个真正的数组。

一段时间以来,有人提议将一个Elements类作为 Array 的真正子类,并将用作“新的 NodeList”。但是,这已从 DOM Standard 中删除,至少目前是这样,因为由于各种技术和规范相关的原因,它尚不可行。

"破坏网络" != "破坏谷歌内容"
2021-03-17 14:10:03
对我来说似乎是一个坏电话。说真的,我认为偶尔破坏一些东西是正确的决定,特别是如果这意味着我们未来拥有健全的 API。此外,它不像网络甚至接近于成为一个稳定的平台,人们已经习惯了他们 2 岁的 JavaScript 不再按预期运行..
2021-03-18 14:10:03
为什么不直接从 Array.prototype 借用 forEach 方法呢?例如,不要添加 Array 作为原型,只需在构造函数中执行 this.forEach = Array.prototype.forEach ,或者甚至只是为 NodeList 唯一地实现 forEach ?
2021-03-23 14:10:03
笔记; 此更新NodeList now has forEach() in all major browsers似乎暗示 IE 不是主流浏览器。希望这对某些人来说是真的,但对我来说不是这样(目前)。
2021-04-05 14:10:03
奇怪的是,截至 2021 年 11 月,它仍未包含在 whatwg 规范中。
2021-04-07 14:10:03

你可以做

Array.prototype.forEach.call (nodeList, function (node) {

    // Your code here.

} );
Array.prototype.forEach.call 可以缩短为 [].forEach.call
2021-04-06 14:10:03
@CodeBrauer:这不仅仅是缩短Array.prototype.forEach.call,它还创建了一个空数组并使用了它的forEach方法。
2021-04-11 14:10:03

您可以考虑创建一个新的节点数组。

  var nodeList = document.getElementsByTagName('div'),

      nodes = Array.prototype.slice.call(nodeList,0); 

  // nodes is an array now.
  nodes.forEach(function(node){ 

       // do your stuff here.  

  });

注意:这只是我们在这里创建的节点引用列表/数组,没有重复的节点。

  nodes[0] === nodeList[0] // will be true
我也建议走样在foreach功能使得:var forEach = Array.prototype.forEach.call(nodeList, callback);现在你可以简单地调用forEach(nodeList, callback);
2021-03-17 14:10:03
或者就这样做Array.prototype.forEach.call(nodeList, fun)
2021-04-04 14:10:03

永远不要说永远,现在是 2016 年,NodeList对象已经forEach在最新的 chrome (v52.0.2743.116) 中实现了一个方法。

现在在生产中使用它为时过早,因为其他浏览器尚不支持此功能(已测试 FF 49),但我猜这将很快标准化。

尽管已实施,但它不是任何标准的一部分。最好仍然Array.prototype.slice.call(nodelist).forEach(…)是标准的并且可以在旧浏览器中使用。
2021-04-04 14:10:03
Opera 也支持它,并且将在 Firefox v50 中添加支持,预定于 15/11/16 发布。
2021-04-07 14:10:03

简而言之,实现该方法存在设计冲突。

来自 MDN:

为什么我不能在 NodeList 上使用 forEach 或 map?

NodeList 的使用与数组非常相似,并且很容易在它们上使用 Array.prototype 方法。然而,这是不可能的。

JavaScript 具有基于原型的继承机制。数组实例继承数组方法(例如 forEach 或 map),因为它们的原型链如下所示:

myArray --> Array.prototype --> Object.prototype --> null (一个对象的原型链可以通过多次调用Object.getPrototypeOf获得)

forEach、map 等都是 Array.prototype 对象的属性。

与数组不同,NodeList 原型链如下所示:

myNodeList --> NodeList.prototype --> Object.prototype --> null

NodeList.prototype 包含 item 方法,但不包含 Array.prototype 方法,因此它们不能用于 NodeLists。

来源:https : //developer.mozilla.org/en-US/docs/DOM/NodeList(向下滚动到为什么我不能使用 forEach 或在 NodeList 上映射?

那么,既然是列表,为什么要这样设计呢?是什么阻止了他们制作链条:myNodeList --> NodeList.prototype --> Array.prototype --> Object.prototype --> null
2021-04-02 14:10:03