先记住这个答案
1e3 是 JavaScript 的数字字面量写法,表示 1 乘以 10 的 3 次方,也就是 1000。e 后面的数字是 10 的指数,可以是正数也可以是负数:1e-3 就是 0.001。这种写法在词法阶段就被解析成普通数字了,和运行时写 1 * 1000 的结果一样,但它不是在做乘法运算。
1e3是 1000,1e-3是 0.001Number能识别指数写法- 极大或极小的数会自动用科学计数法显示
- 指数太大会溢出到
Infinity
指数表示法的基本规则
e 前面是底数,后面是 10 的指数。底数可以是小数,指数必须是整数,可以带正号或负号。写成大写 E 也行,1E3 和 1e3 完全等价。
console.log(1e3); // 1 * 10^3
console.log(2.5e2); // 2.5 * 10^2
console.log(1e-3); // 1 * 10^(-3)
console.log(1e0); // 1 * 10^0
console.log(1e20); // 很大的整数
console.log(1e-7); // 很小的小数查看输出与解释
1000
250
0.001
1
100000000000000000000
1e-7最后一行 1e-7 打印出来还是科学计数法,因为小数点后位数太多时 JavaScript 会自动用这种格式显示。这个格式只影响输出,值本身就是 0.0000001。
在代码里常见的用法是 6e4 表示 60000 毫秒(一分钟),1e6 表示一百万。比起写一串零,指数表示法不容易数错位数。
parseInt 和 Number 对指数的处理完全不同
这是面试里最容易答错的点。Number("1e3") 返回 1000,因为它走的是 ToNumber,能识别指数表示法。但 parseInt("1e3") 返回 1,因为 parseInt 从左往右扫描,遇到 e 这个非数字字符就停了。
console.log(Number('1e3'));
console.log(parseInt('1e3'));
console.log(Number('2.5e2'));
console.log(parseInt('2.5e2'));查看输出与解释
1000
1
250
2parseInt 不仅不认 e,连小数点也不认——parseInt('2.5e2') 只取到 2 就停了。如果你需要把字符串转成数字并且字符串里可能有指数写法,应该用 Number() 或者一元 + 运算符。
还有一个更隐蔽的坑:parseInt 接收的参数如果不是字符串,会先调用 toString()。所以 parseInt(1e21) 实际上是 parseInt("1e+21"),结果是 1 而不是预期的那个大数。当数字本身就很大,toString() 输出了科学计数法字符串,parseInt 就解析不对了。
容易答错的地方
- 认为指数表示法是运行时乘法
1e3不是先算10 ** 3再乘以1。它在代码被解析时就变成了数字1000,和字面量1000没有任何区别。typeof 1e3就是"number",不存在"指数类型"这种东西。- 以为
parseInt能处理指数字符串 parseInt("1e3")返回1,不是1000。面试中如果被问到"怎么把带指数的字符串转成数字",答parseInt就错了,应该用Number()或一元+。
面试官还会怎么问?
什么时候引擎会自动用科学计数法显示数字?
整数部分超过 21 位,或者小数点后连续零超过一定位数时,toString() 会自动输出科学计数法。比如 (1e21).toString() 输出 "1e+21" 而不是一长串数字。这只是显示格式的选择,值本身不变。
指数太大会怎样?
超过双精度浮点数能表示的范围就会溢出到 Infinity。1e308 还能表示,1e309 就变成 Infinity 了。反过来,1e-324 左右是最小的正数,再小就变成 0。
0.1 + 0.2 的精度问题和指数表示法有关系吗?
没有直接关系。0.1 + 0.2 !== 0.3 是因为十进制小数在二进制浮点里无法精确表示,和指数表示法这种语法无关。不过理解 IEEE 754 的指数和尾数结构有助于搞清楚为什么会有精度误差。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。