[1,3,11].map(parseInt) result in
[1, NaN, 3]?
It is common for new developers to be unaware of how map works and how it feeds parameters to the function it is provided. We're all aware that the first parameter it gives is the element in the array we're currently iterating over.
[1,3,11].map(element => console.log(element)) gives us an output that lists 1, 3, 11.
But the fact is, map actually feeds three parameters to the given function. Map provides the current element being iterated over, the current index we're at, and the array being iterated over.
[1,3,11].map((element, index, array) => //... )
We can see this by changing our console.log by referring to it directly rather than wrapping it in an anonymous function:
[1,3,11].map(console.log) 1 0 [ 1, 3, 11 ] 3 1 [ 1, 3, 11 ] 11 2 [ 1, 3, 11 ]
This is pasted directly from the node REPL. You can see here, we get on each line, the element, the index, and the array.
So back to the original problem, why do we get
[1, NaN, 3]?
Because these three arguments are being passed into
parseInt. I believe that many new developers forget that
parseInt actually takes two arguments, more than they would forget that
map provides three arguments.
parseInt takes a number and the radix. The radix tells
parseInt which number system we're using. 0 is decimal, 2 is binary, 3 is trinary, 8 is octal, 16 is hex, and so on and so forth.
parseInt(11, 3) outputs
2 because that's it's trinary equivalent.
So on each pass in
parseInt looks like this:
parseInt(1, 0); parseInt(3, 1); parseInt(11, 2);
The array argument is ignored because
parseInt only takes two arguments. The number provided becomes the element from the array and the radix comes from the index.
On the first pass, we're converting 1 to decimal, which is of course, 1. A radix of 0 and 10 are decimal, so nothing changes with decimal numbers. On the second pass, we get
NaN because the value
1 is invalid for a radix. And on the third pass, we're converting
11 in binary is of course,
3. We have a 1 in the 2^1 position and a 1 in the 2^0 position, 2^1 + 2^0 = 2 + 1 = 3.
In short, the reason we get unexpected values, is because
map provides more arguments to the
parseInt function than we desired.
The solution is very simple, we don't directly pass a reference to a function like
map. Instead, it's best to wrap it in an anonymous function first:
[1, 3, 11].map((element, index, array) => parseInt(element) );
Of course you can omit the
arrayparameters if you aren't using them, I left them in for illustration
Then you can pass your arguments to the function as needed.
Now this is only necessary for functions that take, or potentially take, multiple arguments. If you want to map with a function that only takes one argument, feel free to pass it the reference directly.
const square = x => x * x; [1,2,3].map(square); // [1, 4, 9]
Just be careful to be sure whatever you pass into
map, and this goes for
foreach and many of the other array methods as well, only takes one argument.
You can read more about how
parseInt works on the Mozilla Developer Network here.