Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"[].forEach"?​​

Tags:

javascript

I saw this script somewhere else, and it will check every single checkboxes:

[].forEach.call(document.querySelectorAll('input[type="checkbox"]'),function(el){
       el.checked=true;
    }
);​

I know how to use forEach:

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

//0
//1
//2

But now, it is [].forEach, and there is nothing inside. So why does it still work? Why can't I do this instead?

document.querySelectorAll('input[type="checkbox"]').forEach(function(el){
       el.checked=true;
    }
);​
like image 611
Derek 朕會功夫 Avatar asked Jun 07 '12 00:06

Derek 朕會功夫


3 Answers

JavaScript has first-class functions; that is, they're treated like objects, and can have their own properties and methods. The built in Function.call method takes a this parameter for the function as its first argument, and the rest of the arguments are passed to the function itself. The array [] is not used, except as a means to access the (less concise, so less used) Array.prototype.forEach method.

It's basically a rebinding of Array.forEach for use on something that is not an array, in this case a NodeList. If NodeLists offered a forEach method, then it would be equivalent to, and you may read it as, this:

document.querySelectorAll('input[type="checkbox"]').forEach(function(el) {
   el.checked = true;
});​

So, a little more in depth. call will execute a function with a different context. forEach iterates over the context and calls the function it is passed as its argument. So a someFunc.call(thisArg, otherArg) will be executed as if it were in the context of thisArg, like thisArg.someFunc(otherArg). Here's the simplest example:

function callMe(something) {
    return something + this;
}

callMe('Hello'); // Hellonull or Hello[object Window] or something
callMe.call({}, 'World'); // World[object Object]

apply() works the same way, but you pass an array of arguments as the second argument.

like image 59
Ry- Avatar answered Sep 22 '22 23:09

Ry-


This is just using [] to get the forEach function. Once it has the function, it uses .call to call it as if it was a method of document.querySelectorAll('input[type="checkbox"]').

This is useful because the result of document.querySelectorAll is not an Array but behaves just like one, so we can reuse the standard Array methods.

When you use .call, the first argument is used as the this value. That is, in this particular snippet, every time this is encountered inside the source of forEach, it is set to document.querySelectorAll('input[type="checkbox"]').

You can't just call document.querySelectorAll('input[type="checkbox"]').forEach(... directly because querySelectorAll does not return an Array object and so does not have a forEach method. The whole .call thing is just a way to get around this by calling forEach as if it was a method of NodeList, which is what is actually returned.

like image 31
Tikhon Jelvis Avatar answered Sep 23 '22 23:09

Tikhon Jelvis


Notice the .call. It applies (sets this to) the results of document.querySelectorAll to forEach, so that it iterates over those results rather than the (empty) array on the left-hand side of the dot.

like image 45
josh3736 Avatar answered Sep 19 '22 23:09

josh3736