这事说出来有点尴尬。我一直以为 ['1', '2', '3'].map(parseInt)
会返回 [1, 2, 3]
,直到最近碰到了一个诡异的 bug,才意识到自己一直理解错了。
运行这段代码:
js
console.log(['1', '2', '3'].map(parseInt));
你会得到:
js
[1, NaN, NaN]
是不是感觉哪不对劲?
map 和 parseInt 怎么就掰了?
先简单回顾下两个函数的参数形式:
js
arr.map((value, index, array) => {})
parseInt(string, radix)
重点在这里:map
会把当前值、索引、原数组都传进去。而 parseInt
的第二个参数是 进制,不是索引。
所以上面这段代码,其实执行的是:
js
parseInt('1', 0); // 1,自动识别为十进制
parseInt('2', 1); // NaN,1进制非法
parseInt('3', 2); // NaN,2进制没有 3
结果自然就变成 [1, NaN, NaN]
。
正确做法其实很简单
只要你别让 parseInt
误收到第二个参数就行了。
方法一:包一层箭头函数
js
['1', '2', '3'].map(str => parseInt(str)); // [1, 2, 3]
方法二:直接用 Number
js
['1', '2', '3'].map(Number); // [1, 2, 3]
这个方式更直观,也更不容易踩坑。
为什么这个问题容易被忽略?
主要两个原因:
- 平时我们都把
parseInt
当作"字符串转数字"的函数,很少注意它的第二个参数是进制。 - 写
map(parseInt)
也没有语法错误,但参数传错了,结果就全乱了。
这种问题不容易第一时间发现,尤其调试时根本不会去怀疑 map(parseInt)
这行写法。
顺带说一下:parseInt 和 map 到底是干嘛的?
parseInt
是干嘛的?
parseInt
用来把字符串转成整数:
js
parseInt('10'); // 默认是十进制,结果 10
parseInt('10', 2); // 二进制,结果 2
parseInt('A', 16); // 十六进制,结果 10
parseInt('abc'); // 转不了数字,结果 NaN
注意:第二个参数是"进制",合法范围是 2 到 36。
map
是干嘛的?
map
是数组的方法,用来生成一个新数组,对每一项做处理:
js
['1', '2', '3'].map(x => Number(x)); // [1, 2, 3]
users.map(user => ({
...user,
online: true
}));
跟 forEach
不一样,map
会返回新数组。
写法对比一览表
写法 | 结果 | 是否推荐 |
---|---|---|
['1','2','3'].map(parseInt) |
[1, NaN, NaN] |
❌ 不推荐 |
['1','2','3'].map(str => parseInt(str)) |
[1, 2, 3] |
✅ 推荐 |
['1','2','3'].map(Number) |
[1, 2, 3] |
✅ 推荐 |
总结一句话
别再用 map(parseInt)
,会出问题。
这不是语法错,是你传错了参数。改成箭头函数或者用 Number
,就不会踩坑。
如果你也遇到过类似的"奇怪行为"
欢迎评论区一起交流。我踩过坑,你就别踩了。
如果这篇文章对你有点帮助,点个赞/收藏就当是支持一下~