为什么在字符串数组上使用Array.map(parseInt)会产生不同的结果

Amr*_*raz 2 javascript functional-programming parseint

我正在观看关于破坏所有软件标题Javascript的诞生和死亡的谈话

在演讲中,Gary Bernhardt指出了一个JavaScript古怪的特性,给出了一个整数字符串数组,

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

Array.map() 获取一个函数并返回一个新数组,其结果是在每个运算符上应用此函数.

我发现这个行为起初非常奇怪,不会parseInt将数字解析为整数?

为什么会这样NaN?然后不是10 !!

Amr*_*raz 6

JavaScript通常是模仿的主题,因为它看似意外的结果.

var a = []+{} // [Object object]
var b = {}+[] // 0
Run Code Online (Sandbox Code Playgroud)

然而,它的疯狂是一致的,我怀疑这种parseInt行为背后必然有一些原因.

深入了解正在发生的事情

我首先考虑调试parseInt,但由于无法调试本机函数,我想把它包装在另一个基本上做同样事情的函数.

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]
Run Code Online (Sandbox Code Playgroud)

好的,好像一切都运转正常

但为了简洁起见,我决定尝试一些更多的观察

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]
Run Code Online (Sandbox Code Playgroud)

也许这毕竟不是那么奇怪

在这一点上,结果看似奇怪,它们是一致的(在某种程度上),肯定有一种模式.

然后它打了我. Array.map(callback)回调需要3个参数,(key, index, array)所以如果parseInt不是只采用一个参数而是采用2个参数.

这肯定会对其结果产生影响

结果parseInt()函数解析字符串参数并返回指定基数或基数的整数.

句法 parseInt(string, radix);

基数是数字的基数

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
//...
Run Code Online (Sandbox Code Playgroud)

因为map's回调中的第二个参数是基数根据索引不断变化的索引.

这解释了为什么我的intParse功能有效.我特意定义它只使用了'parseInt'.

我以为这就是地图里面发生的事情

var intParse = function (x) { return parseInt(x);}
Run Code Online (Sandbox Code Playgroud)

事实上,这就是发生的事情

var intParse = function (x, r, array) { return parseInt(x, r);}
Run Code Online (Sandbox Code Playgroud)

在包装函数时我应该做的就是不假设参数传递的方式如此

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]
Run Code Online (Sandbox Code Playgroud)

得到教训

这是一个很好的探索,我想我学到的东西比我想的还要多parseInt.

更重要的是,我被提醒说,当程序以一种意想不到的方式行事时,很可能是有原因的.

最后,如果想要正确包装函数使用 .apply(this, arguments)