forEach() vs Array.prototype.forEach.call()

This is interesting question. Half a year ago I would say that link.forEach is not about shorter syntax, but it is actually not supposed to work. Then I would explain what it means that many of array methods deliberately generic, which means that their internal implementation only considers numeric indexes and length property of the this object, but doesn't care about it being Array instance. Basically what @Pedro Castilho said in his answer.

However, now I will say that these days evergreen browsers (except IE11, Edge, as of April 2017) already implemented NodeList.prototype.forEach convenience method so you no longer need to use .call hack or Array.from in order to just iterate NodeList with forEach.

So my summary: if you don't need to support IE, then use NodeList.prototype.forEach rather than Array.prototype.forEach. It might be the same internally, but cleaner conceptually. If you do need to support IE and you don't want to include one more pollyfill then use Array.prototype.call or better Array.from.


"class methods" in JavaScript are actually functions defined on a prototype. That means that even if an object does not inherit from the Array prototype, you can call Array methods on it, as long as it follows the array structure (i.e.: It is an object with a length property and properties indexed by integers). However, the object holds no reference to Array.prototype, so you need to explicitly select Array.prototype as the object the method lives in.

The document.querySelectorAll function returns a NodeList, which is neither an Array nor inherits from the Array prototype. However, as a NodeList has a similar internal structure to an Array, you can still use the forEach function. But since NodeList does not inherit from the Array prototype, trying to use .forEach on a NodeList would raise an error (this is not exactly true - see the note at the end of my answer). For this reason, you need to explicitly state that you are calling a method from Array.prototype on the NodeList, and that is done by using the .call method from Function.prototype.

In summary:

Array.prototype.forEach.call(links, function(link) { /* something */ })

means:

Take the forEach function from Array.prototype and call it on links, which is a non-Array object, with some function as its argument.

Note that on recent versions of browsers, the NodeList prototype does provide a forEach method which works the same as the Array one, so the example from the Electron API is probably using the Array version for compatibility with older versions. If you have a web app and only care about supporting modern versions of Chrome and Firefox, you can just call forEach on your NodeList. In fact, since Electron updates about 2 weeks after whenever Chrome updates, it should be safe to use NodeList.prototype.forEach in Electron. :)

Tags:

Javascript