I have been refreshing my JavaScript knowledge of call()
and map()
usage on NodeList
.
It was fairly easy to google out, what call()
should be doing and there are resources with examples of how it works with map()
.
However, as I noticed on MDN, the map()
function can also take a second argument, which should be setting the this
keyword for map()
- or at least that is what I think it should be doing.
I have tried to check it myself with simple arrays:
var numbers = [1, 2, 3];
var letters = ['a', 'b', 'c'];
..and with a simple function, that is about to be given as a parameter to map()
:
var effector = function (x) {
console.log(x);
}
Now, what I do not understand, is why these two function calls have different results:
numbers.map(effector, letters);
numbers.map.call(letters, effector);
I expect them to both output letters to the console, as both this
keywords should be referencing to them (respectively to their objects).
I did some further research, and tried with this modified effector function:
var effector = function () {
console.log(this);
}
..again on:
numbers.map(effector, letters);
numbers.map.call(letters, effector);
Assuming, that we are in "use strict", the first call logs letters
and the second logs undefined
.
But again, I would expect both these calls to produce the same output.
What am I missing?
EDIT:
I was reading, how .map
can be polyfilled, if you check it on MDN, there you see, how the second parameter of .map is used in callback.call()
.
I suppose, that in the end, even that callback.call()
should have the same this
as was in .map
.
There are two bindings of the this
reference at play here:
this
for the execution context of the map
functionthis
for the execution context of the callback functionThey don't relate to each other.
The second argument of map
dictates what this
will be for the callback. If it is not provided, the default is undefined
(not the array).
The first argument of map.call
dictates what this
will be for map
-- and by consequence which array will be iterated.
This is also reflected in the polyfill provided on mdn: it is perfectly in line with these specifications: O
gets the value of this
for the map
function, and T
gets the value of this
for the callback. They are generally different.
map
versus forEach
Unrelated to your question, but worth mentioning: don't use map
when you are not actually mapping anything. map
is intended for creating a new array, one in which every value has been mapped by calling the callback function on the original value at that same index.
When however you just need to iterate the array values, without any intent to perform such mapping, then use the forEach
method, or a for...of
loop. Both these work on NodeList
out of the box, without the need to .call
.