Why Does Parseint Yield Nan With Array#Map

Why does parseInt returns NaN when used with Array.map?

Because map adds a second and third parameters: the index and the array itself. See:

["1234-04-23", "1234", "04", "23"].map(console.log);
// => 1234-04-23 0 ["1234-04-23", "1234", "04", "23"]
// => 1234 1 ["1234-04-23", "1234", "04", "23"]
// => 04 2 ["1234-04-23", "1234", "04", "23"]
// => 23 3 ["1234-04-23", "1234", "04", "23"]

As you can see in the specification, parseInt also accepts a second parameter as base, so you are actually doing this:

console.log(["1234-04-23", "1234", "04", "23"].map((e, e2) => parseInt(e, e2)));
// => [1234, NaN, 0, 2]

The NaN is because:

parseInt stops at the first invalid character and returns whatever it
has at that point. If there are no valid characters to parse, it
returns NaN

Source: https://stackoverflow.com/a/39147168/1525495

Why does parseInt yield NaN with Array#map?

The callback function in Array.map has three parameters:

From the same Mozilla page that you linked to:

callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed."

So if you call a function parseInt which actually expects two arguments, the second argument will be the index of the element.

In this case, you ended up calling parseInt with radix 0, 1 and 2 in turn. The first is the same as not supplying the parameter, so it defaulted based on the input (base 10, in this case). Base 1 is an impossible number base, and 3 is not a valid number in base 2:

parseInt('1', 0); // OK - gives 1
parseInt('2', 1); // FAIL - 1 isn't a legal radix
parseInt('3', 2); // FAIL - 3 isn't legal in base 2

So in this case, you need the wrapper function:

['1','2','3'].map(function(num) { return parseInt(num, 10); });

or with ES2015+ syntax:

['1','2','3'].map(num => parseInt(num, 10));

(In both cases, it's best to explicitly supply a radix to parseInt as shown, because otherwise it guesses the radix based on the input. In some older browsers, a leading 0 caused it to guess octal, which tended to be problematic. It will still guess hex if the string starts with 0x.)

Why does JavaScript's map and parseInt function return NaN every other call?

According to the documentation, parseInt accepts two parameters: string integer and base. At the same time, map passes two arguments: value and index.

So, basically your call is equivalent to this:

["6", "1", "0", "3", "3"].map((value, index) => parseInt(value, index))

which results into NaN when it is not possible to parse it with given parameters.

Particularly:

  • parseInt("6", 0) is working, because it seem to use default base (10)
  • parseInt("1", 1) is failing, because 1 is invalid base
  • parseInt("0", 2) is working, it is a binary representation of decimal 0
  • parseInt("3", 3) is failing, because there can be no "3" in base 3
  • parseInt("3", 4) is working, it is a 4-base representation of decimal 3

JavaScript Array.map(parseInt) causes NaN error

parseInt is often used with one argument, but takes two.

The first is an expression and the second is the radix.

To the callback function, Array.prototype.map passes 3 arguments to parseInt: the element, the index, the array.

The third argument is ignored by parseInt, but not the second one, hence the possible confusion.

Why does using Array.map(parseInt) on an array of strings produce different results

JavaScript is often the subject of parody, for its seemingly unexpected results.

var a = []+{} // [Object object]
var b = {}+[] // 0

However there is consistency in its madness, and I suspected the parseInt behavior must have some reason behind it.

Getting to the bottom of what's happening

I first thought of debugging parseInt, but since couldn't debug a native function, I thought of wrapping it around another function that basically does the same thing.

var a = ['10','10','10','10']
var intParse = function (x) {
return parseInt(x);
};

console.log(a.map(parseInt)); // [10, NaN, 2, 3, 4]
console.log(a.map(intParse)); // [10,10,10,10]

Ok so it seems like everything is working fine

But just for the sake of brevity I decided to try some more observations

var a;

(a = Array(13).join('10,').split(',')).pop() // try array of 13 '10's
a.map(parseInt); // [10, NaN, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

(a = Array(10).join('100,').split(',')).pop() // try array of 10 '100's
a.map(parseInt); // [100, NaN, 4, 9, 16, 25, 36, 49, 64, 81]

(a = Array(10).join('7,').split(',')).pop() // try array of 10 '6's
a.map(parseInt); // [7, NaN, NaN, NaN, NaN, NaN, NaN, 6, 6, 6]

Maybe it's not that weird after all

At this point as weird as the results may seem, they are consistent (in some way), there certainly seems to be a pattern.

It then hit me.
Array.map(callback) the callback takes 3 parameters, (key, index, array), so what if parseInt doesn't just take one parameter but 2 instead.

That would certainly had an effect on its results

Turns out The parseInt() function parses a string argument and returns an integer of the specified radix or base.

Syntax
parseInt(string, radix);

the radix is the base of the number

parseInt("10", 0) // 10, zero meant decimal
parseInt("10", 1) // NaN, since only 0 is allowed in base 1
parseInt("10", 2) // 2, '10' in binary
parseInt("10", 3) // 3, '10' in ternary
//...

Since the second argument in map's callback is the index the radix kept changing according to the index.

This explains why my intParse function worked.
I had specifically defined that it uses 'parseInt' with just x.

I thought this was what's happening inside map

var intParse = function (x) { return parseInt(x);}

When in fact this is what was happening

var intParse = function (x, r, array) { return parseInt(x, r);}

What I should've done when wrapping the function was
to not assuming the arguments that where being passed like so

var a = ['10','10','10','10']
var intParse = function () {
return parseInt.apply(this, arguments);
}
console.log(a.map(parseInt)); // [10, NaN, 2, 3, 4]
console.log(a.map(intParse)); // [10, NaN, 2, 3, 4]

Lessons learned

This was a nice exploration, I think I wound up learning a bit more than I thought I would about parseInt.

More importantly tho I was reminded that when programs act in an unexpected way, it is most likely for a reason.

Finally, if one wants to properly wrap a function use .apply(this, arguments)

Javascript: Inconsistent behavior with bound function in `some` array function

Array.some() passes 3 arguments to the callback function: the current array element, its index, and the array.

String.endswith() takes an optional second argument, which is used as the length of the string instead of its actual length.

So the first iteration calls

f('s', 0, ['s', 'q', 'q'])

which is equivalent to

"sss".endsWith('s', 0)

If you use 0 as the length of the string, it doesn't end with s, so this returns false.

When you use your function value => f(value), the extra arguments are discarded so the default length is used and the function operates as expected.



Related Topics



Leave a reply



Submit