遍历 NodeList:Array.prototype.forEach.call() vs Array.from().forEach

Loop through NodeList: Array.prototype.forEach.call() vs Array.from().forEach

所以我想要一个简单的方法来遍历节点列表,我一直讨厌我不能在节点列表上使用 forEach

所以,现在我这样做:Array.prototype.forEach.call(nodeList, callback)

对于索引,我这样做:Array.prototype.indexOf.call(nodeList, node)

几乎所有我都在 nodeLists 上使用 Array.prototype。

但我想知道这些是否被认为是黑客?

它们是正确的方法吗?

此外,假设我实际上不需要来自 nodeList 的数组,那么使用 Array.from(nodeList).forEach(callback) 是否有优势?

Array.prototype.forEach.call(nodeList, callback) 将在节点列表上应用 forEach 的逻辑。 forEach 中只有一个 for 循环,从索引 0this.length 并在每个项目上调用回调。此方法调用 forEach 将节点列表作为其 this 值传递,因为节点列表具有与数组相似的属性(length01、 ...),一切正常。

Array.from(nodeList).forEach(callback) 将从节点列表创建一个新数组,然后在该新数组上使用 forEach。第二种方法可以分为两条自解释行:

var newArray = Array.from(nodeList);  // create a new array out of the node list
newArray.forEach(callback);           // call forEach on the new array

第一种方法更好,因为它不会创建额外的不需要的资源,而且它直接作用于节点列表。

var array=Array.from(nodeList);
//after some time
var array2=Array.from(nodeList);

如果比较这些数组,您会发现它们不一定相等。 NodeLists 反映了 DOM 的变化,当你复制它们时,数组保持静态。如果你想要这种行为/不关心你很好。然而 Array.from 是相当新的,因此它不被旧浏览器理解,所以它不应该在生产环境中使用(如果你不使用像 Babel 这样的东西)。

第一种方法兼容ES5:

Array.prototype.forEach.call(nodeList, callback).

第二种方法使用Array.from,它只在ES6中定义:

Array.from(nodeList).forEach(callback)

但是,您并未在此处优化 Array.from 的使用,因为您首先创建了整个数组,然后使用 forEach.

对其进行迭代

而是使用 Array.from 的第二个参数:

Array.from(nodeList, callback)

现在整个操作在一次迭代中发生。

好的是,在上面的表达式中,回调被用作映射函数,所以如果它return是一个值,整个表达式returns 由那些 return 值定义的数组。但是使用它当然是可选的。例如,您可以创建一个包含节点文本内容的数组,如下所示:

texts = Array.from(nodeList, node => node.textContent)