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;
}
);
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 NodeList
s 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.
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.
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.
If 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