在Ja vaScript开发中,parseInt() 这个函数大家再熟悉不过了。但你是否知道,省略它的第二个参数,就像在代码里埋下了一颗定时冲击波?这绝不是危言耸听,而是一个必须遵守的铁律:永远不要省略 parseInt() 的第二个参数。否则,你的代码行为将变得不可预测,尤其是在跨环境、跨版本,或者与 map 这类数组方法配合时,很容易产出 NaN 或错误的数值,调试起来让人头疼不已。
基数不传,JS 就要“猜心思”
当你写下 parseInt(“010”) 时,你以为它返回的是十进制的10?引擎可不一定这么想。它得根据字符串的前缀来“猜”你到底想用什么进制:
- 如果字符串以
“0x”或“0X”开头,它会按十六进制(radix = 16)来解析。 - 如果以
“0”开头,情况就复杂了。这涉及到历史遗留问题:ES3规范默认是八进制,而ES5及以后的规范改成了十进制。但问题在于,一些旧版本的Safari、IE等浏览器,可能依然遵循老规则。 - 其他所有情况,才会默认按十进制处理。
看到了吗?同一行代码,在不同的浏览器或Node.js版本中运行,parseInt(“010”) 可能返回8,也可能返回10。你根本无法通过肉眼静态地判断结果,一旦出了问题,排查的难度可想而知。
map 中直接传 parseInt 是经典翻车现场
下面这个例子堪称经典陷阱,很多开发者都曾在此失足:
写 [‘1’,‘2’,‘3’].map(parseInt),你期望得到 [1, 2, 3] 吗?现实会给你一个冷酷的答案:[1, NaN, NaN]。
为什么会这样?我们来拆解一下:
map方法在调用回调函数时,会自动传入三个参数:当前元素、当前索引、原数组本身。parseInt函数恰好接受两个参数:要解析的字符串和基数。- 所以,实际执行的是:
parseInt(‘1’, 0)→ 基数0被视同十进制,返回1。parseInt(‘2’, 1)→ 基数1是非法的(有效范围是2–36),返回NaN。parseInt(‘3’, 2)→ 在二进制里,根本没有字符“3”,自然也返回NaN。
这不是bug,而是 map 的自动传参机制与 parseInt 的双参数签名共同作用下的必然结果。一个看似简洁的写法,背后却隐藏着逻辑的崩塌。
合法基数范围很窄,越界即失效
parseInt 的第二个参数 radix,其合法值是一个相当狭窄的区间:必须是2到36之间的整数。一旦越界,函数会直接返回 NaN,没有任何商量余地。
parseInt(“10”, 1)→NaN(基数太小)parseInt(“z”, 37)→NaN(基数太大)parseInt(“10”, 8)→8(合法的八进制解析)parseInt(“ff”, 16)→255(合法的十六进制解析)
如果你不显式地传递这个参数,就等于放弃了对这个关键阈值的控制权,同时也掩盖了代码中可能存在的逻辑漏洞。等到问题在特定数据下爆发时,往往为时已晚。
正确写法:始终显式声明进制
那么,正确的姿势是什么?很简单:不管你的数据看起来多么“理所当然”是十进制,都请明确写出基数参数。
- 解析十进制:
parseInt(“123”, 10) - 解析十六进制:
parseInt(“0xFF”, 16)或parseInt(“FF”, 16) - 解析二进制:
parseInt(“1010”, 2) - 消除歧义:
parseInt(“010”, 10)明确告诉引擎和后来的阅读者:“我就是要解析成十进制的10,不是八进制的8”。
养成这个习惯,好处是显而易见的。你的代码会变得可读、可测、可维护。别人一眼就能看懂你的意图,即便是半年后的你自己回头再看,也不会对着代码发懵。这一个小小的改动,换来的是代码健壮性和团队协作效率的巨大提升,何乐而不为呢?
