Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does [].forEach.call() do in JavaScript?

People also ask

How does array forEach work in JavaScript?

The forEach() method executes a function once for each item in the array. The method is called on the array object that you wish to manipulate, and the function to call is provided as an argument. In the code above, console. log() is invoked for each element in the array.

What does forEach method do in JavaScript?

forEach() The forEach() method executes a provided function once for each array element.

What is array prototype forEach call?

Description. forEach() executes the provided callback once for each element present in the array in ascending order. It is not invoked for index properties that have been deleted or are uninitialized (i.e. on sparse arrays). callback is invoked with three arguments: the element value.

Does forEach return an array JavaScript?

The forEach method does not return a new array like other iterators such as filter , map and sort . Instead, the method returns undefined itself. So it's not chainable like those other methods are.


[] is an array.
This array isn't used at all.

It's being put on the page, because using an array gives you access to array prototypes, like .forEach.

This is just faster than typing Array.prototype.forEach.call(...);

Next, forEach is a function which takes a function as an input...

[1,2,3].forEach(function (num) { console.log(num); });

...and for each element in this (where this is array-like, in that it has a length and you can access its parts like this[1]) it will pass three things:

  1. the element in the array
  2. the index of the element (third element would pass 2)
  3. a reference to the array

Lastly, .call is a prototype which functions have (it's a function which gets called on other functions).
.call will take its first argument and replace this inside of the regular function with whatever you passed call, as the first argument (undefined or null will use window in everyday JS, or will be whatever you passed, if in "strict-mode"). The rest of the arguments will be passed to the original function.

[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
    console.log(i + ": " + item);
});
// 0: "a"
// 1: "b"
// 2: "c"

Therefore, you're creating a quick way to call the forEach function, and you're changing this from the empty array to a list of all <a> tags, and for each <a> in-order, you are calling the function provided.

EDIT

Logical Conclusion / Cleanup

Below, there's a link to an article suggesting that we scrap attempts at functional programming, and stick to manual, inline looping, every time, because this solution is hack-ish and unsightly.

I'd say that while .forEach is less helpful than its counterparts, .map(transformer), .filter(predicate), .reduce(combiner, initialValue), it still serves purposes when all you really want to do is modify the outside world (not the array), n-times, while having access to either arr[i] or i.

So how do we deal with the disparity, as Motto is clearly a talented and knowledgeable guy, and I would like to imagine that I know what I'm doing/where I'm going (now and then... ...other times it's head-first learning)?

The answer is actually quite simple, and something Uncle Bob and Sir Crockford would both facepalm, due to the oversight:

clean it up.

function toArray (arrLike) { // or asArray(), or array(), or *whatever*
  return [].slice.call(arrLike);
}

var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);

Now, if you're questioning whether you need to do this, yourself, the answer may well be no...
This exact thing is done by... ...every(?) library with higher-order features these days.
If you're using lodash or underscore or even jQuery, they're all going to have a way of taking a set of elements, and performing an action n-times.
If you aren't using such a thing, then by all means, write your own.

lib.array = (arrLike, start, end) => [].slice.call(arrLike, start, end);
lib.extend = function (subject) {
  var others = lib.array(arguments, 1);
  return others.reduce(appendKeys, subject);
};

Update for ES6(ES2015) and Beyond

Not only is a slice( )/array( )/etc helper method going to make life easier for people who want to use lists just like they use arrays (as they should), but for the people who have the luxury of operating in ES6+ browsers of the relatively-near future, or of "transpiling" in Babel today, you have language features built in, which make this type of thing unnecessary.

function countArgs (...allArgs) {
  return allArgs.length;
}

function logArgs (...allArgs) {
  return allArgs.forEach(arg => console.log(arg));
}

function extend (subject, ...others) { /* return ... */ }


var nodeArray = [ ...nodeList1, ...nodeList2 ];

Super-clean, and very useful.
Look up the Rest and Spread operators; try them out at the BabelJS site; if your tech stack is in order, use them in production with Babel and a build step.


There's no good reason not to be able to use the transform from non-array into array... ...just don't make a mess of your code doing nothing but pasting that same ugly line, everywhere.


The querySelectorAll method returns a NodeList, which is similar to an array, but it's not quite an array. Therefore, it doesn't have a forEach method (which array objects inherit via Array.prototype).

Since a NodeList is similar to an array, array methods will actually work on it, so by using [].forEach.call you are invoking the Array.prototype.forEach method in the context of the NodeList, as if you had been able to simply do yourNodeList.forEach(/*...*/).

Note that the empty array literal is just a shortcut to the expanded version, which you will probably see quite often too:

Array.prototype.forEach.call(/*...*/);

The other answers have explained this code very well, so I'll just add a suggestion.

This is a good example of code that should be refactored for simplicity and clarity. Instead of using [].forEach.call() or Array.prototype.forEach.call() every time you do this, make a simple function out of it:

function forEach( list, callback ) {
    Array.prototype.forEach.call( list, callback );
}

Now you can call this function instead of the more complicated and obscure code:

forEach( document.querySelectorAll('a'), function( el ) {
   // whatever with the current node
});

It can be better written using

Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {

});

What is does is document.querySelectorAll('a') returns an object similar to an array, but it does not inherit from the Array type. So we calls the forEach method from the Array.prototype object with the context as the value returned by document.querySelectorAll('a')


[].forEach.call( document.querySelectorAll('a'), function(el) {
   // whatever with the current node
});

It is basically the same as:

var arr = document.querySelectorAll('a');
arr.forEach(function(el) {
   // whatever with the current node
});