在JavaScript开发中,字符串与数字之间的类型转换是每个开发者必须掌握的基础技能。本文将从底层原理到实际应用场景,深度剖析7种字符串转数字的方法及其隐藏特性,并通过20+个代码示例揭示常见陷阱。
| console.log(Number("42")); |
| console.log(Number("3.14")); |
| console.log(Number("0xFF")); |
| console.log(Number("123e-2")); |
| console.log(Number("")); |
| console.log(Number("12a")); |
| console.log(Number(true)); |
| console.log(Number(false)); |
核心原理:
- 执行ECMAScript标准的ToNumber抽象操作
- 空字符串转换为0
- 忽略前后空格但中间有非数字字符返回NaN
- 支持科学计数法和进制转换
性能基准测试(Chrome 115):
| |
| console.time("Number"); |
| for(let i=0; i<1e6; i++) Number("123.45"); |
| console.timeEnd("Number"); |
| console.log(+"42"); |
| console.log(+"3.14"); |
| console.log(+"0o77"); |
| console.log(+"Infinity"); |
| console.log(+"12px"); |
| console.log(+""); |
| console.log(+null); |
| console.log(+undefined); |
与Number()的区别:
| const str = "123"; |
| console.log(Number(str) === +str); |
性能对比:
| console.time("Unary Plus"); |
| for(let i=0; i<1e6; i++) +"123.45"; |
| console.timeEnd("Unary Plus"); |
| console.log(parseInt("42px")); |
| console.log(parseInt("101", 2)); |
| console.log(parseInt("0x1F")); |
| console.log(parseInt("3.14")); |
| console.log(parseInt(" 123")); |
| console.log(parseInt("abc")); |
关键特性:
- 自动截断非数字后缀
- 第二个参数指定基数(2-36)
- 0x开头的字符串识别为十六进制
- ES5后前导0不再默认八进制
常见陷阱:
| parseInt("09", 10); |
| parseInt("09"); |
| parseInt("0.1"); |
| parseInt(1/0, 19); |
| console.log(parseFloat("3.14.15")); |
| console.log(parseFloat("3e2")); |
| console.log(parseFloat("0xFF")); |
| console.log(parseFloat("123a")); |
| console.log(parseFloat("Infinity")); |
与Number()对比: | 特征 | parseFloat | Number | |----------------|------------|-----------| | 前导空格 | 忽略 | 忽略 | | 数字+非数字 | 截断 | NaN | | 空字符串 | NaN | 0 | | null | NaN | 0 | | 十六进制 | 不识别 | 识别 |
| console.log(~~"12.99"); |
| console.log("5.87" | 0); |
| console.log("123" >> 0); |
| console.log(+"Infinity" | 0); |
实现原理:
- 所有位运算符操作前都会执行ToInt32转换
- 相当于先执行Number()再执行按位操作
- 只能得到32位有符号整数
适用场景:
- 快速取整
- 将NaN转换为0
- 性能敏感场景(比parseInt快3倍)
| console.log(new Date("2023").getTime()); |
| console.log(Date.parse("2023-07-01")); |
特殊用法:
| const timestamp = +new Date("2023-01-01"); |
| console.log(timestamp); |
| console.log(Number.parseInt === parseInt); |
| console.log(Math.trunc("42.9")); |
| console.log(BigInt("123")); |
新型API对比: | 方法 | 返回值类型 | 特性 | |------------------|------------|------------------------| | Number.parseInt | number | 同全局parseInt | | Number.parseFloat| number | 同全局parseFloat | | Math.trunc | number | 直接截断小数部分 | | BigInt | bigint | 处理大于2^53的整数 |
- 表单验证:
| function validateNumber(input) { |
| const num = +input; |
| return typeof num === 'number' && |
| !isNaN(num) && |
| isFinite(num); |
| } |
- 科学计算精度处理:
| function toPrecision(str, precision=2) { |
| return (+str).toFixed(precision); |
| } |
- 大数据转换优化:
| |
| const strArray = ["1", "2", "3"]; |
| const float32 = new Float32Array(strArray.length); |
| strArray.forEach((s, i) => float32[i] = +s); |
| |
| Method | Time(ms) |
| ----------------|--------- |
| Number() | 38 |
| parseInt | 72 |
| parseFloat | 68 |
| 一元加号 | 35 |
| 位运算(|0) | 28 |
| Math.floor | 45 |
优化建议:
- 优先使用一元加号或位运算符
- 避免在循环中使用parseInt/parseFloat
- 对已知格式的字符串使用定制解析
- 八进制陷阱:
| parseInt("012"); |
| parseInt("012", 8); |
- 大数精度丢失:
| console.log(+"9007199254740993"); |
| |
| BigInt("9007199254740993") |
- 自动类型转换问题:
| 1 + "2" = "12" |
| 1 + +"2" = 3 |
- 非数字的NaN判断:
| isNaN(+"abc") |
| Number.isNaN(+"abc") |
| Object.is(+'abc', NaN) |
场景 |
推荐方法 |
示例 |
严格数字验证 |
Number() |
Number("123") |
CSS单位剥离 |
parseInt |
parseInt("100px") |
浮点转换 |
parseFloat |
parseFloat("3.14") |
性能敏感代码 |
一元加号 |
+"123" |
取整操作 |
位运算符 |
"45.6" | 0 |
大整数处理 |
BigInt |
BigInt("123456789") |
日期转换 |
Date.parse() |
Date.parse(dateStr) |
微信扫一扫:分享
微信里点“发现”,扫一下
二维码便可将本文分享至朋友圈。