Live data from Hacker News

Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

medium.com

51–60 of 163 posts

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#51
post #4

This isn't strange or surprising. parseInt takes two arguments, the second one is the radix and map will call with three arguments, the value, the index and the whole array. You just have to know this and it might be different in other languages. [ ... ].map(x => ...) is the right way to do this.

The surprising bit comes in with the fact that: 1. parseInt is used with only a single argument in most cases. 2. Only the first argument of map is used in most cases. Using multiple parameters for those are so uncommon that it's easy not to realise that it's supported. _If you know all of that_ it may not be surprising to you, but in most cases there is no need for the average developer to know it, making it very su…

There's some interesting history for awareness of the first issue: parseInt used to be a notorious source of bugs and so it used to be more common to see it with a second argument on any project which used a linter in that era.

ES5 deprecated that behaviour and it's been widespread enough that code which started in the IE9+ era now looks like the very old buggy code omitting the radix, so anyone getting started relatively recently quite reasonably may never have needed to learn about it:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... https://eslint.org/docs/rules/radix

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#52
post #24
post #11

Earlier quoted context omitted.

Why would it drive you crazy? This is an example of someone not even knowing how the map function works.

Once you work with several languages it’s really hard to keep track of all this stuff. I never know what exactly evaluates to true vs false in PHP or JavaScript for example. Add to that sloppy programmers on your team who don't check their assumptions it’s really easy to have a ton of subtle bugs in your code.

> I never know what exactly evaluates to true vs false in PHP or JavaScript for example.

You don't have to know if you don't use implicit type-casting. Make it explicit and you won't really have to worry about it.

"Explicit is better than implicit" is part of the Zen of Python for a very good reason.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#53
post #28

Disclaimer: I don't know Javascript, but that's why: > ['1','7','11'].map(console.log) 1 0 [ '1', '7', '11' ] 7 1 [ '1', '7', '11' ] 11 2 [ '1', '7', '11' ] [ undefined, undefined, undefined ] > parseInt(1,0) 1 > parseInt(7,1) NaN > parseInt(11,2) 3 The correct way is: > ['1','7','11'].map(x => parseInt(x)) [ 1, 7, 11 ] same as: > ['1','7','11'].map(x => parseInt(x, 10)) [ 1, 7, 11 ]

Those are unfortunately not the same. The second one (with an explicit radix of 10) is correct; the first is not (or is at least a bit riskier). See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... (ctrl+f for "always").

But see also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... and especially https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... — that comment is increasingly stale unless you support browsers which are no longer supported by their vendors like IE8.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#54
post #17

Easy fix ['1', '7', '11'].map(Number)

Agreed. Number is not only more obvious than parseInt for other coders but also defaults to base 10, whereas parseInt (at least historically) does not (edit: ...if you've got leading zeros, see post below).

parseInt will use the first few characters in the string as a heuristic to determine the radix. It’s not reliable for some types of common decimal strings(padded zeros will cause erroneous parsing)

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#55
So in summary:

JS map doesn't behave like anybody else's map.

JS argument passing prefers doing the wrong thing to interrupting the programmer.

These two things conspire together and poor parseInt does its best with the resulting garble.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#56
post #4

This isn't strange or surprising. parseInt takes two arguments, the second one is the radix and map will call with three arguments, the value, the index and the whole array. You just have to know this and it might be different in other languages. [ ... ].map(x => ...) is the right way to do this.

I've developed applications in JS, but don't have extensive experience with it, and I couldn't spot the problem. Frankly, I think if `['1', '2'].map(parseInt)` is both valid and does not result in a collection containing the integers 1 and 2 in that order, that indicates a catastrophic failure of design at some level. These things happen, but usually you have to dig down to a less bog standard example to find it. The "you just have to know" argument is often unavoidably valid, but in this case I think it's way off the mark.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#58
post #4

This isn't strange or surprising. parseInt takes two arguments, the second one is the radix and map will call with three arguments, the value, the index and the whole array. You just have to know this and it might be different in other languages. [ ... ].map(x => ...) is the right way to do this.

The surprising bit comes in with the fact that: 1. parseInt is used with only a single argument in most cases. 2. Only the first argument of map is used in most cases. Using multiple parameters for those are so uncommon that it's easy not to realise that it's supported. _If you know all of that_ it may not be surprising to you, but in most cases there is no need for the average developer to know it, making it very su…

Well, the average developer should use a lint tool with Javascript.

A bunch of confusion points in Javascript (including this one) have been well understood for a long time, best practices have been developed to deal with them, and mature tooling exists to easily enforce them.

Put another way: If you are unsure, go download eslint along with the plugins for your environment, and find/create a ruleset that turns on almost everything.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#59

Earlier quoted context omitted.

That's apologist talk pure and simple. The language, silently, does something that's almost certainly wrong. The language has enough information to provide you with a helpful warning or error message that you probably don't want to do this, but instead, it violates the principle of least surprise by just doing the wrong thing instead. The correct error is something along the lines of: let numbers = input.iter().map(p…

The map function fully expects a function with two arguments, as per documentation. Why would passing a function that takes two arguments to map be an error?

The example given is taken from Rust. Rust does not allow overloading (even in terms of optional parameters, I believe). Well, Rust allows overloading by implementing different traits but then forces you to disambiguate where necessary.

Re: Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript

#60

Disclaimer: I don't know Javascript, but that's why: > ['1','7','11'].map(console.log) 1 0 [ '1', '7', '11' ] 7 1 [ '1', '7', '11' ] 11 2 [ '1', '7', '11' ] [ undefined, undefined, undefined ] > parseInt(1,0) 1 > parseInt(7,1) NaN > parseInt(11,2) 3 The correct way is: > ['1','7','11'].map(x => parseInt(x)) [ 1, 7, 11 ] same as: > ['1','7','11'].map(x => parseInt(x, 10)) [ 1, 7, 11 ]

What does parseInt work with a radix of 0 but not 1? Neither really makes any sense.
Post reply on HN