我正在查找如何迭代 NodeLists 并且遇到了以下代码。
var nodesArray = Array.prototype.slice.call(nodeList);
nodesArray.forEach(function(node) {
//...
})
调用Array.prototype.slice
NodeList 的目的是什么?
我正在查找如何迭代 NodeLists 并且遇到了以下代码。
var nodesArray = Array.prototype.slice.call(nodeList);
nodesArray.forEach(function(node) {
//...
})
调用Array.prototype.slice
NodeList 的目的是什么?
调用
Array.prototype.slice
NodeList 的目的是什么?
该Array#slice
方法“将数组的一部分的浅拷贝返回到新的数组对象中”。
该Function#call
方法“使用给定的 this 值和单独提供的参数调用函数”。
因为数组是对象,所有的对象属性名称都存储为字符串,并且所有的节点列表都使用顺序编号的属性名称存储它们的元素(再次存储为字符串),节点列表可以用作this
数组方法的值。
将 NodeList 的浅表副本创建为 Array 允许您在新创建的 Array 上使用其他 Array 方法,而无需使用Function#call
.
许多现代浏览器已经实现NodeList#forEach
了 ,尽管该方法仍然是一个候选推荐,并且目前尚未将其纳入规范。我建议谨慎使用该方法,而不是在开放的网络上,直到它达到更稳定的状态。
以下是使用 NodeList 作为目标调用 Array 方法的其他一些示例:
// Convert to an array, then iterate
const nodeArray = Array.prototype.slice.call(nodeList)
nodeArray.forEach(doSomething);
// Iterate NodeList directly without conversion
Array.prototype.forEach.call(nodeList, doSomething);
// Perform operation on each element in NodeList, output results to a new Array
Array.prototype.map.call(nodeList, function(item) {
return item;
}).forEach(doSomething);
// Filter NodeList, output result to a new Array
Array.prototype.filter.call(nodeList, function(item) {
return /* condition */;
}).forEach(doSomething);
还有许多其他方法可以迭代不需要使用 Array 方法的 NodeList,这里有更多示例:
您可以使用老式的 for 循环,从零开始循环,直到到达数组的末尾。这种方法一直存在,今天仍然经常使用。与此处提到的其他方法相比,这种方法的可读性稍差一些,但这一切都归结为您更容易编写的方法。
for(let i = 0; i < nodeList.length; ++i) doSomething(nodeList[i]);
由于缺少条件评估,使用向后循环(在可能的情况下)可以节省执行时间。事实上,有些 IDE 默认会将前面的循环转换为下面的结构。
for(let i = nodeList.length; i--;) doSomething(nodeList[i]);
您可以使用 while 循环,它需要一个条件语句作为其参数。如果NodeList.item(n)
超出 NodeList 的边界,它将返回 null,这将结束循环。
let i = 0, node;
while((node = nodeList.item(i++))) doSomething(node);
您可以在条件中使用 for 循环执行相同的操作:
let node;
for(let i = 0; (node = nodeList.item(i)); i++) doSomething(node);
您可以使用 for...in 循环和Object.keys()
. 请注意,Object.keys
在使用 for...in 循环时必须使用,否则它将遍历不可枚举的属性以及可枚举的属性。
Object.keys() 方法返回给定对象自己的可枚举属性的数组,其顺序与 for...in 循环提供的顺序相同(不同之处在于 for-in 循环将原型链中的属性枚举为出色地)。
来自: https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
for(var i in Object.keys(nodeList)) doSomething(nodeList[i]);
for...of
您可以通过从 Array() 检索 Iterator 函数并将其应用于 NodeList来使用循环(ECMAScript 2015+)。只要属性是可枚举的,这也适用于对象的大多数其他用途。
nodeList[Symbol.iterator] = [][Symbol.iterator];
for(node of nodeList) doSomething(node);
如果将 Array Iterator 应用于 NodeList 类的原型,那么每当创建 NodeList 的新实例时,它将始终是可迭代的。但是,不建议扩展原生原型。
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
for(node of nodeList) doSomething(node);
使用 forEach 方法迭代 NodeList
但我不明白为什么我们使用 slice 方法?
没必要,直接就可以
Array.prototype.forEach.call(nodelist, function(value, index) {
...
});
所有这些答案都已过时。实际上,您可以forEach
在现代浏览器中的 NodeList 上使用!
所以只需使用forEach!
因为slice
返回任何类似数组的参数的副本作为新的数组对象,这正是我们所需要的。我们可以很容易地使用concat
.