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

天大地大妈咪最大 提交于 2019-12-01 08:12:48

问题


I was watching a talk on destroy all software title The Birth and Death of Javascript

during the talk Gary Bernhardt pointed out a JavaScript quirky features, were given an array of integer strings,

javascript
var a = ['10','10','10','10']
console.log(a.map(parseInt)); // [10, NaN, 2, 3, 4]

Array.map() takes a function and returns a new array with the result of applying this function on each operator.

I found the behavior incredibly bizarre at first, doesn't parseInt parse a number to an integer?

why would it be NaN? and then not 10!!


回答1:


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)



来源:https://stackoverflow.com/questions/24046827/why-does-using-array-mapparseint-on-an-array-of-strings-produce-different-resu

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!