使用forEach方法迭代NodeList [英] Iterate a NodeList using forEach method

查看:196
本文介绍了使用forEach方法迭代NodeList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用forEach方法遍历一个NodeList,我搜索了这个方法,我发现解决方案是将NodeList转换为一个数组:

  var nodesArray = Array.prototype.slice.call(nodeList); 

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

解决方案

迭代NodeList有很多种方法。

一般而言,将nodeList转换为Array或使用Array的函数引用nodeList并不是一个好主意。

你可以使用一个很好的老式循环,从零开始循环,直到到达数组的末尾。这种方法一直存在,现在仍然使用。这种方法的可读性比这里提到的其他方法要少一些,但是这一切都归结为你写得更容易。

 <$ c $ (var i = 0; i< nodeList.length; ++ i)doSomething(nodeList [i]); 

有些人会告诉你,使用向后循环将节省计算周期手段。实际上,一些IDE实际上将默认情况下将前一个循环转换为以下结构。实际上,微观优化是不被接受的。 这个方法和这里提到的其他方法在性能上没有实质性的区别。

  for (var i = nodeList.length-1; i> -1; -i)doSomething(nodeList [i]); 

你可以使用一个while循环,它需要一个条件语句作为它的参数。如果 NodeList.item(n)超过了NodeList的范围,它将返回null,这将结束循环。

  var i = 0; ((node = nodeList.item(i ++)))doSomething(node); 
while

另一种使用for循环的方法,类似于while循环。一个传统的for循环的中间条件需要一个条件语句,就像上面的while循环一样,所以这个工作。

  for(var i = 0;(node = nodeList.item(i)); i ++)doSomething(node); 

您可以使用for ... in循环与 Object.keys )。请注意,在使用for ... in循环时,您必须使用 Object.keys ,否则它将遍历不可枚举的属性以及可枚举的属性。 / b>


Object.keys()方法以与for提供的顺序相同的顺序返回给定对象自己可枚举属性的数组。 ..in循环(区别在于for-in循环枚举了原型链中的属性)。
From: https://developer.mozilla.org/zh-CN/docs/Web/ JavaScript / Reference / Global_Objects / Object / keys




  (var i在Object.keys(nodeList))doSomething(nodeList [i]); 

在ES6中,您可以使用for ... of循环通过从Array检索Iterator函数)并将其应用于NodeList。只要属性是可枚举的,这也适用于大多数对象的使用。

  nodeList [Symbol.iterator ] = [] [Symbol.iterator]; 
for(节点nodeList)doSomething(节点);

另外,你在这里做的是从数组中检索Symbol.iterator函数并将其应用到NodeList对象的原型。这样,无论何时创建一个新的NodeList,它总是会有迭代器,所以你只需要在脚本开始的时候这样做。



(function(){use strict; NodeList.prototype [Symbol.iterator] = [] [Symbol.iterator]; for(let document.querySelectorAll('*'))document.body.innerHTML + = document.body.innerHTML + ='< br>'; for(让document.querySelectorAll('*:not(body)'))的节点document.body.innerHTML + = node.tagName +'';})();

b
$ b




前面提到的每种方法都有各种各样的变化,也许还有其他的方法,这里我没有记录,但是上面介绍的方法给了你如何迭代NodeList没有欺骗阵列功能。


$ b


我想用forEach方法迭代NodeList
blockquote>

为什么?这是真正的问题。虽然你可以通过欺骗一个数组函数来相信NodeList是一个Array来迭代NodeList,你为什么要这样做?

lockquote

我搜索了这个方法,我发现解决方案是将NodeList转换为一个数组。 >是的,这是劫持一个数组函数,以迭代一个NodeList。


但我不明白我们为什么用切片方法?

Array.prototype.slice()元素从原始数组中复制。使用 .call()可以让我们将这个的值补充到我们NodeList的 slice ()



Array.prototype.slice.call(NodeList) strong>表示对象可枚举属性的浅表副本的数组



有很多方法劫持Array函数并欺骗它们,使其认为它们正在工作与一个数组,同时给他们一个对象。

我个人认为以下任何一种方法都是可怕的代码,但是,因为你问了一下,我会包含任何相关的数组函数可以在NodeList上使用。

  Array.prototype.slice.call(nodeList).forEach(doSomething); 



  []。slice.call(nodeList).forEach做一点事); 

您不需要从NodeList中创建一个数组,您可以简单地使用<$ c直接在 forEach 函数上使用$ c> .call()。

pre > Array.prototype.forEach.call(nodeList,doSomething);



  []。forEach.call(nodeList,doSomething); 

或者您可以使用map根据公式从nodeList创建一个新数组,然后迭代NodeList使用forEach。

$ p $ Array.prototype.map.call(nodeList,function(item){
return item;
})。forEach(doSomething);



  []。map.call(nodeList,function(item ){
return item;
})。forEach(doSomething);

这些工作是因为一个Array是一种Object,而一个NodeList与一个Array相似你可以使用NodeList的一些数组函数。然而,这些方法不应该被鼓励,有很多更好的方法来迭代NodeList






最后,如果您不想劫持任何数组函数,但想要使用forEach,则可以从NodeList构建一个数组。

  var array = new Array(els.length); 
for(var key in Object.keys(nodeList))arrary [key] = nodeList [key];
array.forEach(doSomething);

这是多余的,因为您基本上是迭代NodeList两次。






这里要注意的重要一点是,就性能而言,这两种方法之间并没有真正的实际差异。所有这些方法的执行速度都是相似的,如果你的迭代过程中有足够的元素,那么你应该问自己是否有更好的方法正在采取解决你的问题。



至于哪种方法比其他方法更好,这一切都取决于你的感受是什么,更容易理解,你觉得最舒适的写作。
$ b

JSPerf结果






目前我个人最喜欢的方法,直到ES6成为当前的标准,是while循环方法。在我看来,这是迭代NodeList最可读的方法。



var els = document.getElementsByTagName('i'),i = 0 ,el; while((el = els.item(i ++)))el.innerHTML + ='*';

 < i> Hello< / i> < I> FOO< / I> < I>巴≤; I> /; < i> >  

I want to iterate a NodeList using forEach method, I googled about the method, and I found the solution to do that is to convert the NodeList to an Array :

var nodesArray = Array.prototype.slice.call(nodeList);

But I don't understand why we used the slice method ?

解决方案

There are many ways to iterate a NodeList.

In general, it is not a good idea to turn a nodeList into an Array or to use an Array's functions in reference to a nodeList.

You can use a good old fashioned for loop, start at zero and loop until we reach the end of the array. This method has been around for ever and is still used regularly today. This method is, somewhat, less readable than other methods mentioned here, but it all comes down to what is easier for you to write.

for(var i = 0; i < nodeList.length; ++i)  doSomething(nodeList[i]);

Some people will tell you that using a backwards for loop will save "computation cycles", whatever that really means. In fact, some IDEs will actually convert the previous loop to the following structure by default.

In reality, micro-optimization is frowned upon. There is no real tangible difference in performance between this method and the other methods mentioned here.

for(var i = nodeList.length - 1; i > -1; --i)  doSomething(nodeList[i]);

You can use a while loop, which expects a conditional statement as its parameter. If NodeList.item(n) is past the bounds of the NodeList it will return null, which will end the loop.

var i = 0;
while((node = nodeList.item(i++))) doSomething(node);

Another method of using a for loop, which is similar to the while loop. The middle condition of a traditional for loop expects a conditional statement, just like the while loop above, so this works.

for(var i = 0; (node = nodeList.item(i)); i++) doSomething(node);

You can use a for...in loop with Object.keys(). Note that you have to use Object.keys when using a for...in loop because otherwise it will iterate over the non-enumerable properties as well as the enumerable ones.

The Object.keys() method returns an array of a given object's own enumerable properties, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
From: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

for(var i in Object.keys(nodeList))  doSomething(nodeList[i]);

In ES6, you can use a for...of loop by retrieving the Iterator function from Array() and applying it to the NodeList. This will work for most other uses of an object as well, as long as the properties are enumerable.

nodeList[Symbol.iterator] = [][Symbol.iterator];
for(node of nodeList) doSomething(node);

Also, cool enough, the following works in ES6. What you're doing here is retrieving the Symbol.iterator function from the Array and applying that to the NodeList object's prototype. This way, whenever a new NodeList is created, it will always have the iterator, so you only have to do that at the beginning of the script.

(function(){
    "use strict";
    NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
    for(let node of document.querySelectorAll('*')) document.body.innerHTML += node.tagName + ' ';
    document.body.innerHTML += '<br>';
    for(let node of document.querySelectorAll('*:not(body)')) document.body.innerHTML += node.tagName + ' ';
})();


There are variations on each of the previously mentioned methods as well as there are probably other methods that I haven't documented here, but the methods documented above give you the general idea of how you can iterate a NodeList without tricking array functions.


I want to iterate a NodeList using forEach method

Why? That is the real issue here. While you can iterate a NodeList by tricking an array function into believing that a NodeList is an Array, why would you want to?

I googled about the method, and I found the solution to do that is to convert the NodeList to an Array.

Yes, that is one method of hijacking an Array function in order to iterate a NodeList.

But I don't understand why we used the slice method?

Array.prototype.slice() returns a shallow copy of elements from the original array. Using .call() allows us to supplement the value of this to our NodeList for slice().

Array.prototype.slice.call(NodeList) returns an array representing a shallow copy of the object's enumerable properties.

There are numerous methods of hijacking Array functions and tricking them into thinking that they are working with an Array while feeding them an Object.

I personally believe that any of the following methods are horrible code but, because you asked about it, I will include any relevant array functions that can be used on a NodeList.

Array.prototype.slice.call(nodeList).forEach(doSomething);

[].slice.call(nodeList).forEach(doSomething);

You don't need to make an array out of the NodeList, you can simply use .call() on the forEach function directly.

Array.prototype.forEach.call(nodeList, doSomething);

[].forEach.call(nodeList, doSomething);

Or you can use map to create a new array from the nodeList based on a formula, then iterate the NodeList using forEach.

Array.prototype.map.call(nodeList, function(item) { 
    return item; 
}).forEach(doSomething);

[].map.call(nodeList, function(item) { 
    return item; 
}).forEach(doSomething);

These work because an Array is a type of Object, and a NodeList is similar enough to an Array that you can use some of the Array functions with a NodeList.

However, these methods should not be encouraged, there are much better ways to iterate a NodeList


Finally, if you don't want to hijack any array functions, but do want to use forEach, you can build an array from the NodeList.

var array = new Array(els.length);
for(var key in Object.keys(nodeList)) arrary[key] = nodeList[key];
array.forEach(doSomething);

This is somewhat redundant because you are basically iterating the NodeList twice.


The important thing to note here, is that there is no real tangible difference between any of these methods as far as performance is concerned. All of these methods will perform at a relatively similar rate and if you get to a point where you are iterating over enough elements that it would actually matter, you should ask yourself if there is better approach that you should be taking to solve your problem.

As for which method is better than the rest, it all depends on what you feel is more easily understood and what you feel most comfortable writing.

JSPerf results


My personal favorite method at the moment, until ES6 becomes the current standard, is the while loop method. In my opinion it is the most readable method of iterating a NodeList.

var els = document.getElementsByTagName('i'), i = 0, el;

while((el = els.item(i++))) el.innerHTML += '*';

<i>Hello</i> <i>foo</i> <i>bar</i> <i>world</i>

这篇关于使用forEach方法迭代NodeList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆