Last Updated: February 25, 2016
·
1.622K
· piatra

Another valuable use case for .call method

I was working on a project and I have to go through a list of input elements too see if they are checked or not and save the value of the checked ones. First off I selected all of them

var inputs = document.querySelectorAll('input[type="checkbox"]:checked')

That way I only get the ones I want. But now I have to go through each one and check their value (stored in the id of the element). I could use a for loop, or I could use .forEach but that wouldn't work because inputs.forEach is undefined. What now ?

[].forEach.call(inputs, fn (input) { // code } )

Now we have the power of the forEach method, yay!
Or better yet

[].map.call(inputs, function (input) { 
 params.push(input.id);
})

I went on to use the .map method

2 Responses
Add your response

One important thing to note here is this trick is useful for a lot of the array-like Objects that you might encounter in JavaScript. The two most common examples are the arguments variable inside a function body, and a NodeList, which is what gets returned from most DOM methods that return more than one DOM node. These array-like objects basically just have a .length property, and several sequential numerical keys indexed at "0" (remember, the keys of an Object are always strings). I suppose this harkens back to early JavaScript before a proper Array type even existed. It's funny how in most languages an Array is less complex than a hash/dictionary since they use integers as keys, but with JavaScript it's the complete opposite because of the way Objects are the base type and require strings as keys.

Also, are you just using .map for terseness? Because in your last example you're creating an array full of undefineds and not assigning it anywhere. While it's probably trivial, I say use the right tool for the right job, and forEach is that tool, for only 4 keystrokes more. And while terseness is sometimes great, I can't see the logic in instantiating an Array just to get to Array.prototype.forEach or Array.prototype.map. Object caching optimizations still apply though, so if you use these function often, putting a
var forEach = Array.prototype.forEach.call
somewhere in your app will probably speed things up too.

Another trick that people tend to use is:
Array.prototype.slice.call(inputs)
which will coerce any array-like object (or basically any object with a .length property, even strings!) into a fully-fledged Array. This operation is slow, however, and nine times out of ten, the forEach.call or map.call is all what you want out of it anyway, and doing a for loop to iterate over it tends to be faster as well.

over 1 year ago ·

@coverslide In the cases where I am using this, performance isn't an issue, it simply iterates over 6-7 inputs and themap result is stored in a variable. Your point is totally valid, I admit I did not think of performance, I chose this method because I found it to make code more readable.

over 1 year ago ·