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 ?
Because
slice
returns a copy of any array-like argument as a new array object, which is exactly what we need. We could just as easily useconcat
.You don't have to, you could do this directly
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.
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.
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.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.
You can use a for...in loop with
Object.keys()
. Note that you have to useObject.keys
when using a for...in loop because otherwise it will iterate over the non-enumerable properties as well as the enumerable ones.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.
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.
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.
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?
Yes, that is one method of hijacking an Array function in order to iterate a NodeList.
Array.prototype.slice()
returns a shallow copy of elements from the original array. Using.call()
allows us to supplement the value ofthis
to our NodeList forslice()
.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.
You don't need to make an array out of the NodeList, you can simply use
.call()
on theforEach
function directly.Or you can use map to create a new array from the nodeList based on a formula, then iterate the NodeList using forEach.
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.
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.
All these answers are outdated. Actually you can use
forEach
on NodeList in modern browsers!So just use forEach!