I am using a forEach to loop through a nodeList. My code is as follows
var array = document.querySelectorAll('items');
array.forEach(function (item) {
console.log(item);
});
And this code throws an error as
Uncaught TypeError: array.forEach is not a function
Then after reading few online blog articles i changed the code to this.
[].forEach.call(array, (function (item) {
console.log(item);
}));
Could someone please explain why it is not possible to call forEach on a nodeList and what does the above second code piece do. :)
Edit: 7/25/2017
This question does not valid for modern browsers. You can use forEach on node lists in them
Although NodeList is not an Array, it is possible to iterate on it using forEach(). It can also be converted to an Array using Array.from().
However some older browsers have not yet implemented NodeList.forEach() nor Array.from(). But those limitations can be circumvented by using Array.prototype.forEach() (more in this document).
Ref: MDN
The nodeList and a read-only length property and item(index) function to return a node. The answer is, you have to iterate. There is no alternative. Foreach will not work.
The Difference Between an HTMLCollection and a NodeList The index starts at 0. Both have a length property that returns the number of elements in the list (collection). An HTMLCollection is a collection of document elements. A NodeList is a collection of document nodes (element nodes, attribute nodes, and text nodes).
Differences between forEach() and map() methods: The forEach() method does not create a new array based on the given array. The map() method creates an entirely new array. The forEach() method returns “undefined“. The map() method returns the newly created array according to the provided callback function.
No, forEach does not mutate the original array. You can achieve what you are looking for by giving a second parameter of index , then updating the values of the original array.
This is a fundamental thing in JavaScript: you can take a function from one object and apply to any other object. That is: call it with this
set to the object you apply the function to. It is possible, because in JavaScript all property names etc. are (plainly speaking) identified by name. So despite NodeList.length
being something different then Array.length
the function Array.forEach
can be applied to anything that exposes property length
(and other stuff that forEach
requires).
So what happens in your case is that:
querySelectorAll()
returns an object of type NodeList, which happens to expose length
property and is enumerable (let's say it is accessible by []
operator); NodeList does not expose forEach
function (as you can see i.e here: https://developer.mozilla.org/en-US/docs/Web/API/NodeList) - that's why it's impossible to call forEach
directly on the results of querySelectorAll()
[].forEach
returns a function - this a not so clever shortcut for Array.prototype.forEach
[].forEach.call(array, …)
this function is applied onto an object referenced by array
, an object of type NodeList (that is forEach
is invoked with array
as this
in function body, so when inside forEach
there is this.length
it refers to length
in array
despite array
being NodeList and not real Array)forEach
is using properties that Array and NodeList have in common; it would fail if, i.e. forEach
wanted to use some property that Array has, but NodeList has notIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With