Why it is not possible to call forEach on a nodeList?
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 exposelength
property and is enumerable (let's say it is accessible by[]
operator); NodeList does not exposeforEach
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 callforEach
directly on the results ofquerySelectorAll()
[].forEach
returns a function - this a not so clever shortcut forArray.prototype.forEach
- with
[].forEach.call(array, …)
this function is applied onto an object referenced byarray
, an object of type NodeList (that isforEach
is invoked witharray
asthis
in function body, so when insideforEach
there isthis.length
it refers tolength
inarray
despitearray
being NodeList and not real Array) - this works, because
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 not
the NodeList
object doesnt contain the method forEach
, its a method of the Array object. the below code:
[].forEach.call(array, (function (item) {
console.log(item);
}));
is using the forEach
method from array and passing it a NodeList
.
Another option you have, and arguabiliy better, is to convert your NodeList
into an array, like this:
var myArrayOfNodes = [].slice.call(NodeList);
This uses the Array objects slice
method to create an array of nodes from a NodeList
. This is a better aproach as you can then use an array rather then hacking an array-like object