为什么不能在 nodeList 上调用 forEach?
Why it is not possible to call forEach on a nodeList?
我正在使用 forEach 循环遍历 nodeList。我的代码如下
var array = document.querySelectorAll('items');
array.forEach(function (item) {
console.log(item);
});
并且此代码抛出错误
Uncaught TypeError: array.forEach is not a function
然后在阅读了一些在线博客文章后,我将代码更改为这个。
[].forEach.call(array, (function (item) {
console.log(item);
}));
有人可以解释一下为什么不能在 nodeList 上调用 forEach 以及上面第二个代码片段的作用。 :)
编辑: 7/25/2017
此问题不适用于现代浏览器。您可以在其中的节点列表上使用 forEach
Although NodeList is not an Array, it is possible to iterate on it
using forEach(). It can also be converted to an Array using
Array.from().
However some older browsers have not yet implemented
NodeList.forEach() nor Array.from(). But those limitations can be
circumvented by using Array.prototype.forEach() (more in this
document).
参考:MDN
NodeList
对象不包含方法 forEach
,它是 Array object 的方法。下面的代码:
[].forEach.call(array, (function (item) {
console.log(item);
}));
正在使用数组中的 forEach
方法并将其传递给 NodeList
。
你有另一个选择,而且可以说更好,是将你的 NodeList
转换成数组,如下所示:
var myArrayOfNodes = [].slice.call(NodeList);
这使用数组对象 slice
method 从 NodeList
创建节点数组。这是一个更好的方法,因为您可以使用数组而不是破解类似数组的对象
querySelectorAll
获取 array-like
对象中的元素而不是数组。所以你需要像第二个代码示例中那样使用。
这是 JavaScript 中的基本内容:您可以从一个对象中获取一个函数,然后 应用 到任何其他对象。即:将 this
设置为您 应用 函数的对象来调用它。这是可能的,因为在 JavaScript 中,所有 属性 名称等都是(简单地说)由名称标识的。因此,尽管 NodeList.length
与 Array.length
不同,但函数 Array.forEach
可以 应用 到任何暴露 属性 length
的东西(以及 forEach
需要的其他内容)。
所以你的情况是这样的:
querySelectorAll()
returns 类型为 NodeList 的对象,它恰好公开了 length
属性 并且是可枚举的(让我们说 []
运算符可以访问它); NodeList 不公开 forEach
函数(如您所见,即此处:https://developer.mozilla.org/en-US/docs/Web/API/NodeList)——这就是为什么无法直接在结果上调用 forEach
的原因共 querySelectorAll()
[].forEach
returns 一个函数 - 这是 不太聪明 Array.prototype.forEach
的快捷方式
- 与
[].forEach.call(array, …)
此函数 应用 到 array
引用的对象,NodeList[=60= 类型的对象](即 forEach
在函数体中用 array
作为 this
调用,所以当 forEach
里面有 this.length
它指的是 length
在 array
中,尽管 array
是 NodeList 而不是真实的 Array)
- 这是可行的,因为
forEach
使用的是 Array 和 NodeList 的共同属性;如果 forEach
想使用 Array 有的一些 属性,但 NodeList 没有
我正在使用 forEach 循环遍历 nodeList。我的代码如下
var array = document.querySelectorAll('items');
array.forEach(function (item) {
console.log(item);
});
并且此代码抛出错误
Uncaught TypeError: array.forEach is not a function
然后在阅读了一些在线博客文章后,我将代码更改为这个。
[].forEach.call(array, (function (item) {
console.log(item);
}));
有人可以解释一下为什么不能在 nodeList 上调用 forEach 以及上面第二个代码片段的作用。 :)
编辑: 7/25/2017
此问题不适用于现代浏览器。您可以在其中的节点列表上使用 forEach
Although NodeList is not an Array, it is possible to iterate on it using forEach(). It can also be converted to an Array using Array.from().
However some older browsers have not yet implemented NodeList.forEach() nor Array.from(). But those limitations can be circumvented by using Array.prototype.forEach() (more in this document).
参考:MDN
NodeList
对象不包含方法 forEach
,它是 Array object 的方法。下面的代码:
[].forEach.call(array, (function (item) {
console.log(item);
}));
正在使用数组中的 forEach
方法并将其传递给 NodeList
。
你有另一个选择,而且可以说更好,是将你的 NodeList
转换成数组,如下所示:
var myArrayOfNodes = [].slice.call(NodeList);
这使用数组对象 slice
method 从 NodeList
创建节点数组。这是一个更好的方法,因为您可以使用数组而不是破解类似数组的对象
querySelectorAll
获取 array-like
对象中的元素而不是数组。所以你需要像第二个代码示例中那样使用。
这是 JavaScript 中的基本内容:您可以从一个对象中获取一个函数,然后 应用 到任何其他对象。即:将 this
设置为您 应用 函数的对象来调用它。这是可能的,因为在 JavaScript 中,所有 属性 名称等都是(简单地说)由名称标识的。因此,尽管 NodeList.length
与 Array.length
不同,但函数 Array.forEach
可以 应用 到任何暴露 属性 length
的东西(以及 forEach
需要的其他内容)。
所以你的情况是这样的:
querySelectorAll()
returns 类型为 NodeList 的对象,它恰好公开了length
属性 并且是可枚举的(让我们说[]
运算符可以访问它); NodeList 不公开forEach
函数(如您所见,即此处:https://developer.mozilla.org/en-US/docs/Web/API/NodeList)——这就是为什么无法直接在结果上调用forEach
的原因共querySelectorAll()
[].forEach
returns 一个函数 - 这是 不太聪明Array.prototype.forEach
的快捷方式
- 与
[].forEach.call(array, …)
此函数 应用 到array
引用的对象,NodeList[=60= 类型的对象](即forEach
在函数体中用array
作为this
调用,所以当forEach
里面有this.length
它指的是length
在array
中,尽管array
是 NodeList 而不是真实的 Array) - 这是可行的,因为
forEach
使用的是 Array 和 NodeList 的共同属性;如果forEach
想使用 Array 有的一些 属性,但 NodeList 没有