DEV Community

Cover image for Why ['1', '5', '11'].map(parseInt) in JS returns [1, NaN, 3]?
Pablo Veiga
Pablo Veiga

Posted on

Why ['1', '5', '11'].map(parseInt) in JS returns [1, NaN, 3]?

In JavaScript, the map function applies a given function to each element of an array and returns a new array with the results. When you use map with parseInt like ['1', '5', '11'].map(parseInt), the result might not be what you expect due to the way parseInt and map interact. Let's break down what happens.

Understanding parseInt

The parseInt function in JavaScript parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).

parseInt(string, radix)
Enter fullscreen mode Exit fullscreen mode
  • string: The string to be parsed.
  • radix: An integer between 2 and 36 that represents the radix (the base in mathematical numeral systems) of the string.

If radix is not provided, parseInt will use different heuristics to determine the base of the string, which can lead to unexpected results.

The map Function

The map function calls the provided function once for each element in an array, in order, and constructs a new array from the results.

array.map(function(currentValue, index, array) {
  // function body
})
Enter fullscreen mode Exit fullscreen mode
  • currentValue: The current element being processed in the array.
  • index: The index of the current element being processed in the array.
  • array: The array map was called upon.

Combining map and parseInt

When you use parseInt inside map, parseInt is called with two arguments: the element of the array and the index of that element. However, parseInt can take two arguments where the second argument is the radix. So, the index is inadvertently used as the radix.

Here's how it breaks down:

For the first element '1' at index 0:

parseInt('1', 0) // 0 is interpreted as the radix, which defaults to 10
// Result: 1
Enter fullscreen mode Exit fullscreen mode

For the second element '5' at index 1:

parseInt('5', 1) // 1 is interpreted as the radix, but radix 1 is invalid
// Result: NaN (Not a Number)
Enter fullscreen mode Exit fullscreen mode

For the third element '11' at index 2:

parseInt('11', 2) // 2 is interpreted as the radix (binary)
// '11' in binary is 3 in decimal
// Result: 3
Enter fullscreen mode Exit fullscreen mode

Thus, ['1', '5', '11'].map(parseInt) results in [1, NaN, 3].

Correct Usage

To avoid this issue, you can pass a function that only uses the first argument of parseInt and defaults the radix to 10:

['1', '5', '11'].map(str => parseInt(str, 10)) // [1, 5, 11]
Enter fullscreen mode Exit fullscreen mode

or just ommit the radix param:

['1', '5', '11'].map(str => parseInt(str)) // [1, 5, 11]
Enter fullscreen mode Exit fullscreen mode

Here, str is explicitly converted to an integer using a base of 10 for each element in the array, resulting in [1, 5, 11].


Cover image and article content created with the help of AI

Top comments (1)

Collapse
 
oculus42 profile image
Samuel Rouse

This is a very real source of difficult-to-debug issues. Knowing or limiting the number of arguments on both the caller and the callee can be very important.

Libraries like Lo-dash have offered a _.unary() utility to provide this kind of protection as well, but that is more helpful when you are composing functions or do not have full control of the function passed to you. Of course this became much easier since ES6 and arrow functions.