【问题标题】:Why it is not possible to call forEach on a nodeList?为什么不能在 nodeList 上调用 forEach?
【发布时间】:2015-09-29 01:05:03
【问题描述】:

我正在使用 forEach 循环通过 nodeList。我的代码如下

var array = document.querySelectorAll('items');

array.forEach(function (item) {
    console.log(item);
}); 

这段代码抛出了一个错误

未捕获的类型错误:array.forEach 不是函数

然后在阅读了几篇在线博客文章后,我将代码更改为此。

[].forEach.call(array, (function (item) {
    console.log(item);
})); 

谁能解释一下为什么不能在 nodeList 上调用 forEach 以及上面的第二个代码片段是做什么的。 :)

编辑: 7/25/2017

此问题不适用于现代浏览器。您可以在其中的节点列表上使用 forEach

虽然 NodeList 不是 Array,但可以对其进行迭代 使用 forEach()。它也可以使用转换为数组 Array.from().

但是一些旧的浏览器还没有实现 NodeList.forEach() 也不是 Array.from()。但这些限制可以 通过使用 Array.prototype.forEach() 规避(更多在这个 文件)。

参考:MDN

【问题讨论】:

标签: javascript arrays foreach nodelist


【解决方案1】:

这是 JavaScript 中的一项基本功能:您可以从一个对象中获取一个函数,然后应用到任何其他对象。即:调用它时将this 设置为您应用该函数的对象。这是可能的,因为在 JavaScript 中,所有属性名称等都(简单地说)由名称标识。因此,尽管 NodeList.lengthArray.length 不同,但函数 Array.forEach 可以应用到任何暴露属性 length(以及 forEach 需要的其他东西)的东西。

所以你的情况是这样的:

  • querySelectorAll() 返回一个 NodeList 类型的对象,它恰好暴露了length 属性并且是可枚举的(假设它可以被[] 操作符访问); NodeList 不公开 forEach 函数(如您所见,即这里:https://developer.mozilla.org/en-US/docs/Web/API/NodeList) - 这就是为什么不可能直接在 querySelectorAll() 的结果上调用 forEach
  • [].forEach 返回一个函数 - 这是Array.prototype.forEach不太聪明快捷方式
  • 使用[].forEach.call(array, …),此函数应用array引用的对象上,NodeList类型的对象(即forEach被@987654339调用@ 作为函数体中的this,所以当在forEach 中存在this.length 时,它在array 中引用length,尽管arrayNodeList 而不是真正的Array )
  • 这行得通,因为forEach 使用的是 ArrayNodeList 共有的属性;如果,即forEach 想要使用 Array 具有的某些属性,但 NodeList 没有
  • ,它将失败

【讨论】:

  • 现在你可以在nodeList 上使用forEach
【解决方案2】:

NodeList 对象不包含方法forEach,它是Array object 的方法。以下代码:

[].forEach.call(array, (function (item) {
    console.log(item);
})); 

正在使用数组中的forEach 方法并将NodeList 传递给它。

您有另一个选择,而且可以说更好,是将您的 NodeList 转换为数组,如下所示:

var myArrayOfNodes = [].slice.call(NodeList);

这使用数组对象slicemethodNodeList 创建一个节点数组。这是一种更好的方法,因为您可以使用数组而不是破解类似数组的对象

【讨论】:

    【解决方案3】:

    querySelectorAll 获取array-like 对象中的元素而不是数组。所以你需要像第二个代码示例一样使用。

    【讨论】:

    • 对不起,你的意思是什么?
    • 正如您所指出的,querySelectorAll 的返回值不会返回Array,因此我们无法显式调用.forEach。但是,我们可以通过将其作为 this 传递给 forEachduck typing 以完成工作。术语可能不同,但我想这可能是鸭子打字。
    猜你喜欢
    • 2012-11-06
    • 2021-06-18
    • 1970-01-01
    • 2010-11-17
    • 2019-08-06
    • 2015-08-20
    • 2015-07-22
    • 2019-01-29
    相关资源
    最近更新 更多