map functions. As an argument for these functions we can pass lambda expression or function reference. Is there a difference between them? The answer is yes.
What’s the problem?
In our project we are builing a mapping using
String.fromCharCode function. To simplify the usage of this function looked similar to:
[66, 67, 68].map(v => String.fromCharCode(v))
When we run this code with node we received
[ 'B', 'C', 'D' ], but when we decided to refactor it to use function reference the result was different:
> [66, 67, 68].map(String.fromCharCode) [ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]
To find the reason of this behavior, let’s first play with function
> String.fromCharCode(66) 'B' > String.fromCharCode([66, 67, 68]) '\u0000' > String.fromCharCode(66, 67, 68) 'BCD'
String.fromCharCode deals with various types and numbers of arguments.
Now, let’s examine the function
> [66, 67, 68].map(v => v) [ 66, 67, 68 ] > [66, 67, 68].map((v, u) => [v, u]) [ [ 66, 0 ], [ 67, 1 ], [ 68, 2 ] ] > [66, 67, 68].map((v, u, w) => [v, u, w]) [ [ 66, 0, [ 66, 67, 68 ] ], [ 67, 1, [ 66, 67, 68 ] ], [ 68, 2, [ 66, 67, 68 ] ] ]
map, like many other array functions, passes always three arguments to function. First is current value, second is the index of current value and third is the whole array.
It means that passing
map function under the hood looks like this:
> [66, 67, 68].map((v, u, w) => String.fromCharCode(v, u, w)) [ 'B\u0000\u0000', 'C\u0001\u0000', 'D\u0002\u0000' ]
and it is equal to the initial example.
We have to be careful when we want to use a function which can take more than one argument, but we want to pass only the value. We have to pass the function as a lambda expression:
> [66, 67, 68].map(v => String.fromCharCode(v)) [ 'B', 'C', 'D' ]
or create another function which ensures that only the first argument will be passed to desired function:
> const useOnlyValue = f => v => f(v); undefined > [66, 67, 68].map(useOnlyValue(String.fromCharCode)) [ 'B', 'C', 'D' ]