3 ms·
Explain why ['1','1','1'].map(parseInt) returns [1, NaN, 1] but ['1','1','1'].map(n => parseInt(n)) returns [1, 1, 1].
by hkjkahfjddd 8y ago
Explain why ['1','1','1'].map(parseInt) returns [1, NaN, 1] but ['1','1','1'].map(n => parseInt(n)) returns [1, 1, 1].
- contravariant 8y agoWhat the hell, who on earth thought that behaviour would be a good idea?
- jacobwg 8y ago.map(fn) calls its callback with three arguments, the value, the index, and the full array. Then parseInt takes two arguments, the string and the base (radix). "1" of base 0 is 1 "1" of base 1 is NaN "1" of base 2 is 1 The gotcha here is if you map(fn), you're going to get all three arguments sent to the fn, where map(v => fn(v)) explicitly only sends the first one.
- contravariant 8y agoI see. I'll remember this example for when someone asks why you need types.
- shados 8y agothis is more than just types though. Typescript, even in strict mode, will still allow this! You need strict function arity/signature checking of some kind, which a dynamically typed language could have, and a statically typed language could lack.
- contravariant 8y agoIf a language can't detect the difference between a function a => f(a) and a function (a,b) => f(a,b) then I would consider it very weakly typed indeed. Dynamic vs static isn't really the issue, Python will also complain if you call a function with the wrong number of arguments. Then again I suppose that you could recreate JavaScripts behaviour even in the fairly strongly typed C# if you wanted to, by defining two overloaded versions of Map as follows: IEnumerable<B> Map<A,B>(this IEnumerable<B> list, Func<A,B> f) IEnumerable<B> Map<A,B>(this IEnumerable<B> list, Func<A,int,B> f) in that case C# would also choose the latter Map when you call it on a function with an optional int argument, similar to what JavaScript would do. However C# will never ignore an optional argument when you're passing around functions, so it's more consistent in that sense. And overloading a function in this way is not the best idea in the first place, it's just that JavaScript kind of encourages it.
- dzek69 8y agoNobody thought about it or did that on purpose to confuse you with this particular example. If you would do js enough you still could be surprised at first but then you'll see it's pretty valid behavior. map will pass value and key to the method given. so it will call parseInt('1', 0) parseInt('1', 1) parseInt('1', 2)
- DDR0 8y agoNo one ever thought it would be a good idea, Contravariant. :/ It's just an unfortunate interaction between two APIs. Map's callback gets three args, and parseInt takes two (and ignores the third). After a while, you get used to wrapping callbacks to slough off the spare variables as shown. In this case, the index of the element (1, 2, 3) is getting passed as the radix with which to parse the element (1, 1, 1).
- Silhouette 8y agoProbably the same person who thought [1, 2, 3, 4].reduce((x, y) => Math.min(x, y)) should be 1 but [1, 2, 3, 4].reduce(Math.min) should be NaN, for similar reasons. Unfortunately it's a recurring theme in JS that a lot of useful functions have optional extra parameters and a lot of useful higher order functions pass extra context to their callbacks, causing many traps for the unwary if you try to use these tools in a style that works fine in most functional programming languages.
- danielvf 8y agoThanks for the chuckle. To save everyone from having to look this up on Stack Overflow: .map passes two arguments to the function it calls - the value and the index. The parseInt function takes up to two arguments, a string and a radix. So there’s nothing broken here about .map, you just aren’t expecting the second optional argument for parseInt. So the actual equivalents are: ['1','1','1'].map(parseInt) And ['1','1','1'].map((n, index) => parseInt(n, index))
- pseudoramble 8y agoHah! That's amusing. It took me a moment to realize what might be happening, and then another moment to confirm it. Another funny example is: ['1', '2', '3'].map(parseInt) This would be a bummer to be put on-the-spot to answer. It was fun while not being in an interview though.
- vladimir-y 8y agoTry this ['1','1','1'].map(Number). That's just about language specifics, not a question for seniors in my opinion.