[英]Why does parseInt yield NaN with Array#map?
[1,4,9].map(Math.sqrt)
将产生:
[1,2,3]
那么为什么这样做:
['1','2','3'].map(parseInt)
产生这个:
[1, NaN, NaN]
我已经在 Firefox 3.0.1 和 Chrome 0.3 中进行了测试,作为免责声明,我知道这不是跨浏览器功能(没有 IE)。
我发现以下将达到预期的效果。 但是,它仍然没有解释parseInt
的错误行为。
['1','2','3'].map(function(i){return +i;}) // returns [1,2,3]
Array.map
的回调函数有三个参数:
从您链接到的同一个Mozilla 页面:
callback 使用三个参数调用:元素的值、元素的索引和被遍历的 Array 对象。”
因此,如果您调用一个实际需要两个参数的函数parseInt
,则第二个参数将是元素的索引。
在这种情况下,您最终以基数 0、1 和 2 依次调用parseInt
。 第一个与不提供参数相同,因此它基于输入(在本例中为基数 10)进行默认设置。 基数 1 是不可能的数基数,而 3 不是基数 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
所以在这种情况下,你需要包装函数:
['1','2','3'].map(function(num) { return parseInt(num, 10); });
或使用 ES2015+ 语法:
['1','2','3'].map(num => parseInt(num, 10));
(在这两种情况下,最好显式地为parseInt
提供一个基数,如图所示,否则它会根据输入猜测基数。在一些较旧的浏览器中,前导 0 会导致它猜测八进制,这往往是有问题的。它会如果字符串以0x
仍然猜测十六进制。)
map
传递了第二个参数,它(在许多情况下)弄乱了parseInt
的基数参数。
如果您使用下划线,您可以执行以下操作:
['10','1','100'].map(_.partial(parseInt, _, 10))
或不带下划线:
['10','1','100'].map(function(x) { return parseInt(x, 10); });
您可以使用Number作为 iteratee 函数来解决此问题:
var a = ['0', '1', '2', '10', '15', '57'].map(Number); console.log(a);
如果没有 new 运算符,Number 可用于执行类型转换。 但是,它与 parseInt 不同:它不解析字符串并在无法转换数字时返回 NaN。 例如:
console.log(parseInt("19asdf")); console.log(Number("19asf"));
我敢打赌,parseInt 的第二个参数基数会发生一些奇怪的事情。 为什么它在使用 Array.map 而不是直接调用它时会中断,我不知道。
// Works fine
parseInt( 4 );
parseInt( 9 );
// Breaks! Why?
[1,4,9].map( parseInt );
// Fixes the problem
[1,4,9].map( function( num ){ return parseInt( num, 10 ) } );
您可以使用箭头函数 ES2015/ES6 并将数字传递给 parseInt。 基数的默认值为 10
[10, 20, 30].map(x => parseInt(x))
或者您可以明确指定基数以提高代码的可读性。
[10, 20, 30].map(x => parseInt(x, 10))
在上面的示例中,基数显式设置为 10
另一个(工作)快速修复:
var parseInt10 = function(x){return parseInt(x, 10);}
['0', '1', '2', '10', '15', '57'].map(parseInt10);
//[0, 1, 2, 10, 15, 57]
你可以这样解决这个问题:
array.map(x => parseInt(x))
例子:
var arr = ["3", "5", "7"]; console.log( arr.map(x => parseInt(x)) );
出于这个原因,应该避免parseInt
恕我直言。 您可以包装它以使其在这些上下文中更安全,如下所示:
const safe = { parseInt: (s, opt) => { const { radix = 10 } = opt ? opt : {}; return parseInt(s, radix); } } console.log( ['1','2','3'].map(safe.parseInt) ); console.log( ['1', '10', '11'].map(e => safe.parseInt(e, { radix: 2 })) );
lodash/fp 默认将 iteratee 参数设置为 1 以避免这些问题。 就我个人而言,我发现这些变通方法可以避免尽可能多地产生错误。 我认为,将parseInt
列入黑名单以支持更安全的实现是一种更好的方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.