8

我正在查找如何迭代 NodeLists 并且遇到了以下代码。

var nodesArray = Array.prototype.slice.call(nodeList);
nodesArray.forEach(function(node) { 
    //...
})

调用Array.prototype.sliceNodeList 的目的是什么?

4

4 回答 4

15

调用Array.prototype.sliceNodeList 的目的是什么?

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);
于 2015-05-21T23:58:16.763 回答
3

使用 forEach 方法迭代 NodeList

但我不明白为什么我们使用 slice 方法?

没必要,直接就可以

Array.prototype.forEach.call(nodelist, function(value, index) {
    ...
});
于 2014-02-20T22:58:36.307 回答
1

所有这些答案都已过时。实际上,您可以forEach在现代浏览器中的 NodeList 上使用!

所以只需使用forEach

于 2018-04-09T13:38:58.607 回答
0

因为slice返回任何类似数组的参数的副本作为新的数组对象,这正是我们所需要的。我们可以很容易地使用concat.

于 2014-02-20T22:42:27.520 回答