Why can’t I pass directly parseInt to Array.map?
I’d like to share something I learned thanks to the Advent of Code 2021. If you need to convert an array of strings into array of integers (which you’ll need to do often while participating in the advent of code), you might use the Array.map method and the parseInt function and write something like:
['121', '223', '362'].map((string) => parseInt(string));
Which would return an array of integers: [121, 223, 362]
Great, but now, as the middle arrow function only calls parseInt
with the argument it receives, you might want to simplify this statement by passing directly the parseInt
function to the map
method.
['121', '223', '362'].map(parseInt);
I’ve done these kinds of simplifications dozens of times, and it always worked like a charm. But in this particular case, the returned value was not what I expected: [121, NaN, NaN]
What is going on here? Why does the array contains a correct result for the first entry, but NaN
for the second and third? You might think (as I did) that the first and second way of calling parseInt
are similar. So what? It might seem obvious to some readers, but I scratched my head some time to find the answer.
The explanation is that parseInt
can take a second argument to specify the arithmetic base of the string to parse as an int (by default, 10). The exact function signature is parseInt(string, base)
.
Now, the callback function passed as a parameter to the map
method will be called with three arguments : its signature is mapCallback(current, index, array)
. Thus, parseInt
is called with index
as the second parameter base
.
mapCallback(current, index, array);
/* ↓ ↓ */
parseInt(string, base);
So calling the map method on the ['121', '223', '362']
array, parseInt
will be called three times with the following argument :
parseInt('121', 0, ['121', '223', '362']);
parseInt('223', 1, ['121', '223', '362']);
parseInt('362', 2, ['121', '223', '362']);
- calling
parseInt
with0
asbase
returns121
because it falls back to the default value10
* - calling
parseInt
with1
asbase
returnsNan
because base1
makes no sense - when called with
2
asbase
,parseInt
expect to receive a string representing a binary number, ie made of only 1 and 0
So here it is ! If you want to simplify array.map((item) => myFunction(item))
to array.map(myFunction)
, be sure that myFunction
does not expect, as a second argument, something else that the current element index.
- Thanks to my coworker Vincent Hardouin for pointing out that this a gross oversimplification of what really happens. To be safe, you should always specify the
base
argument instead of assuming it will default to10
(MDN explains why here).
Un commentaire ? Une question ?
Utilisez
les issues Github
ou le module ci-dessous !