先记住这个答案
parseInt(string, radix) 的规则是:先把第一个参数转成字符串,去掉开头的空白,识别正负号,然后按进制从左往右读数字字符,遇到第一个不属于该进制的字符就停,返回已经读到的整数部分。一个合法字符都没读到,返回 NaN。所以 parseInt('12px') 是 12,parseInt('px12') 是 NaN。radix 不传时只有 0x 开头会按十六进制,其余按十进制,实际写代码时应该总是传 radix。
- 读到非法字符就停,一个都没读到才是
NaN - 只认
0x前缀,0b、0o和前导 0 都不认 - 参数会先转成字符串,小数可能变成科学计数法
- 永远显式传
radix,一般写 10
几个典型输入
先看一组输出,大部分坑都能在这里找到。
console.log(parseInt(' 42abc')) // 跳过开头空格,读到 a 停下
console.log(parseInt('3.99')) // 小数点不是整数字符,直接截断,不四舍五入
console.log(parseInt('abc42')) // 第一个字符就不合法
console.log(parseInt('')) // 什么都读不到
console.log(parseInt('0x1F')) // 0x 前缀自动按十六进制
console.log(parseInt('0x1F', 10)) // 指定十进制后,读到 x 就停
console.log(parseInt('0b101')) // 不认 0b,读到 b 停
console.log(parseInt('010')) // 前导 0 不再当八进制
console.log(parseInt('1e3')) // e 不是数字,科学计数法不认查看输出与解释
42
3
NaN
NaN
31
0
0
10
1有两行值得单独说。parseInt('0x1F', 10) 返回 0,因为十进制下 x 不合法,只读到了开头的 0。parseInt('010') 返回 10:在很老的引擎里前导 0 会被当成八进制得到 8,ES5 已经明确规定不再这样处理,现在所有主流浏览器都按十进制解析。能被自动识别的前缀只有 0x 和 0X,二进制的 0b、八进制的 0o 只在数字字面量和 Number() 里有效。
两道经典坑题
面试官很喜欢这两道,因为它们分别考了 radix 和「先转字符串」这两条规则。
['1', '2', '3'].map(parseInt)- 结果是
[1, NaN, NaN]。map调用回调时会传三个参数:元素、索引、数组。于是实际执行的是parseInt('1', 0)、parseInt('2', 1)、parseInt('3', 2)。第一个radix是 0,等同于没传,按十进制得 1。第二个radix是 1,不在 2~36 的范围里,直接返回NaN。第三个按二进制解析,二进制里只有 0 和 1,'3'一个合法字符都没有,也是NaN。修法是写成.map((s) => parseInt(s, 10)),或者直接.map(Number)。 parseInt(0.0000005)为什么是 5?parseInt的第一个参数必须是字符串,数字会先经过String()转换。String(0.0000005)得到'5e-7',因为小于 1e-6 的数会用科学计数法表示。接着从左往右读,读到5遇到e停下,结果就是 5。同样的道理,parseInt(1e21)得到 1,因为String(1e21)是'1e+21'。 所以不要用parseInt给数字取整。数字取整用Math.trunc、Math.floor,它们直接对数值操作,不经过字符串。
容易答错的地方
- 以为
parseInt会四舍五入 parseInt('3.99')是 3,parseInt('-3.99')是 -3。它只是在小数点处截断,效果相当于向 0 取整,从来不做舍入。- 以为不传
radix也没问题 - 对十进制字符串确实没问题,但只要数据里混进
0x开头的值,结果就会悄悄变成十六进制。ESLint 的radix规则就是专门要求显式传第二个参数的。 - 以为超长数字串能精确解析
parseInt('9007199254740993')得到 9007199254740992。parseInt能读完所有数字,但结果仍然是 Number,超过 2^53 就会被舍入。需要精确处理大整数时用BigInt('9007199254740993')。
面试官还会怎么问?
parseInt 和 Number() 选哪个?
看你想不想容忍多余字符。解析 '12px' 这种 CSS 值、从一段文本里取开头的数字,用 parseInt;校验用户输入必须是纯数字,用 Number(),因为 Number('12px') 会直接返回 NaN,能把脏数据暴露出来。
parseInt(null, 36) 返回什么?
返回 1112745。null 先被转成字符串 'null',而三十六进制里 n、u、l 都是合法数字,整串被当成一个三十六进制数解析了。这个例子常被用来说明「先转字符串」这条规则。
怎么把十六进制字符串转回数字?
parseInt('ff', 16) 得到 255,带不带 0x 前缀都可以,parseInt('0xff', 16) 也是 255。反过来把数字转成十六进制字符串用 (255).toString(16)。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。