先记住这个答案
Number(str) 和 +str 是同一套规则:去掉首尾空白后,整个字符串必须是一个合法的数字字面量,否则返回 NaN,空串和纯空格得 0。parseInt 和 parseFloat 是另一套规则:跳过开头空白,从左往右读,遇到第一个非法字符就停,把前面那段转成数字,一个字符都读不到才是 NaN。另外 parseInt 只取整数部分、能指定进制,parseFloat 能读小数和科学计数法、只认十进制。
Number()和+规则一致:整串合法才行parseInt遇非法字符会停下- 空串经
Number转换得到 0 parseFloat认科学计数法,不认0x
一张对照表看全差异
同样的字符串分别交给四种写法,差异一目了然。
const inputs = ['42', ' 42 ', '', '12.5px', '3.14', '0x1F', '1e3', '.5', 'Infinity', 'abc']
for (const s of inputs) {
const row = [Number(s), +s, parseInt(s, 10), parseFloat(s)]
console.log(`'${s}'`.padEnd(11), row.join(' | '))
}查看输出与解释
'42' 42 | 42 | 42 | 42
' 42 ' 42 | 42 | 42 | 42
'' 0 | 0 | NaN | NaN
'12.5px' NaN | NaN | 12 | 12.5
'3.14' 3.14 | 3.14 | 3 | 3.14
'0x1F' 31 | 31 | 0 | 0
'1e3' 1000 | 1000 | 1 | 1000
'.5' 0.5 | 0.5 | NaN | 0.5
'Infinity' Infinity | Infinity | NaN | Infinity
'abc' NaN | NaN | NaN | NaN前两列永远一样,因为一元加号内部调用的就是和 Number() 相同的转换。后两列的差异主要来自「读到哪里停」:parseInt 遇到小数点、e 就停,所以 '3.14' 得 3,'1e3' 得 1;parseFloat 能把小数点和指数读进去,但它只认十进制,'0x1F' 读到 x 就停在 0。'.5' 这一行也很典型:parseInt 第一个字符就是小数点,什么都没读到,得 NaN。
注意 parseInt(s, 10) 这里显式传了十进制,所以 '0x1F' 得 0;如果不传 radix,parseInt('0x1F') 会按十六进制得到 31。
不同场景该用哪个
选哪个不看喜好,看你是想「容忍多余字符」还是「发现脏数据」。
- 校验用户输入:用
Number() - 表单里要求输入纯数字时,
Number()最合适,'12abc'会直接变成NaN,脏数据藏不住。它唯一的坑是空串得 0,所以要先判空:input.trim() !== '' && Number.isFinite(Number(input))。 - 解析带单位的值:用
parseFloat或parseInt - 从
getComputedStyle拿到的'12.5px'、从文案里截出的'3 件',本来就带着多余字符,这时要的正是「读开头那个数字」的行为。有小数用parseFloat,确定是整数、或者需要按十六进制解析颜色值这种场景,用parseInt并传入radix。 - 一元加号:只是更短的
Number() +value在需要快速转数字的地方很常见,比如+new Date()取时间戳、+input.value取输入框数值。它和Number()唯一的行为差异在 BigInt:Number(10n)得到 10,+10n会抛TypeError。团队代码里如果觉得+不够显眼,统一写Number()也完全可以。
容易答错的地方
- 以为
Number()会像parseInt一样读开头的数字 Number('12px')是NaN,不是 12。Number()对字符串是全有或全无的。- 以为
parseFloat能解析所有数字写法 parseFloat('0x10')是 0,parseFloat('0b11')也是 0。它只认十进制和科学计数法,进制前缀一概不认。需要解析十六进制只能用parseInt(s, 16)或Number('0x10')。- 以为数字分隔符在字符串里也能用
1_000在代码里是合法的数字字面量,但Number('1_000')是NaN,parseInt('1_000')是 1。分隔符只在源代码的字面量里有效,字符串转换时不认。
面试官还会怎么问?
Number(null) 和 Number(undefined) 分别是什么?
Number(null) 是 0,Number(undefined) 是 NaN。而 parseInt(null) 和 parseInt(undefined) 都是 NaN,因为它们先被转成字符串 'null' 和 'undefined',十进制下一个合法字符都没有。
Number(' \n 12 \t ') 能转成功吗?
能,得到 12。Number() 会去掉首尾的空白字符,包括空格、换行、制表符。但中间有空格就不行,Number('1 2') 是 NaN。
为什么 parseFloat 没有第二个参数?
因为它只处理十进制。带小数的非十进制字符串在实际业务里几乎用不到,规范就没有为 parseFloat 设计 radix 参数。需要其他进制只能用 parseInt,而它只能处理整数。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。