先记住这个答案
数字分隔符是 ES2021 引入的语法,允许在数字字面量里插入下划线来分组,比如把一百万写成 1_000_000。它能用在十进制整数、小数、指数部分,以及 0b、0o、0x 开头的二进制、八进制、十六进制,还有 BigInt 字面量。限制只有一条核心规则:下划线两边都必须是数字。所以放在开头结尾、连写两个、贴着小数点、e、进制前缀或 BigInt 的 n,都会报 SyntaxError。它只是给人看的,编译后数值里没有下划线,Number('1_000') 这类字符串转换也不认它。
_只能出现在两个数字字符之间- 二进制、八进制、十六进制、BigInt、小数和指数都能用
- 前导
0、进制前缀、n后缀旁边都不能放 - 数字分隔符只用于源码字面量
能用在哪些字面量里
最常见的用途是给大数字分组,比如金额、时间毫秒数、文件大小上限。在二进制和十六进制里,按 4 位或按字节分组更能看清每一位的含义,写位掩码、颜色值时特别有用。
const price = 1_000_000 // 十进制整数
const mask = 0b1111_0000 // 二进制按 4 位分组
const color = 0xff_cc_00 // 十六进制按字节分组
const rate = 0.000_001 // 小数部分也能用
const big = 9_007_199_254_740_993n // BigInt 字面量同样支持
console.log(price, mask, color, rate)
console.log(1_000 === 1000) // 只是写法,值完全一样
console.log(String(1_000)) // 输出时不会带下划线
// 字符串转数字时,下划线不被认可
console.log(Number('1_000'), parseInt('1_000'), parseFloat('3_000.5'))查看输出与解释
1000000 240 16763904 0.000001
true
1000
NaN 1 3打印出来的值里完全没有下划线,说明分隔符在解析源码时就被丢掉了,运行时根本不存在。分组方式也没有强制要求,1_0000_0000 按中文的「万」来分同样合法。
最后一行值得多看一眼。Number 遇到下划线直接返回 NaN,parseInt 和 parseFloat 则在遇到下划线时停止解析,只取前面能识别的部分,所以得到 1 和 3。如果配置文件或接口里出现了 '1_000' 这样的字符串,程序不会报错,只会悄悄算错。
写在哪些位置会报错
规则其实就一句话:下划线左右两边都得是当前进制的数字字符。按这个原则去套,下面这些写法全部是语法错误,代码写在注释里,因为它们根本通不过解析。
SyntaxErrorJavaScript// 1_ 结尾
// 1__000 连续两个
// 1_.5 贴着小数点左边
// 1._5 贴着小数点右边
// 1_e5 贴着 e 左边
// 1e_5 贴着 e 右边
// 0x_ff 贴着进制前缀
// 1_000_n 贴着 BigInt 的 n
// 0_1 前导 0 后面
// _1000 不是语法错误,而是被当成变量名,运行时报 ReferenceError前导 0 的限制有历史原因。0 开头再跟数字的写法在非严格模式下曾经表示老式八进制,比如 017 是 15。为了不让 0_17 这种写法产生歧义,规范干脆禁止在前导 0 后面加分隔符,老式八进制字面量里也不允许使用。
_1000 是个特殊情况。以下划线开头的是合法标识符,所以解析器会把它当成变量名,只有在变量不存在时才在运行时报 ReferenceError。如果项目里恰好定义了 _1000 这个变量,代码就会静默地用错值。
- 兼容性和工具链
- 主流浏览器和 Node.js 都已支持这个语法。项目需要兼容很老的浏览器时,Babel 或 TypeScript 在编译时会把下划线去掉,产物里不会留下这个语法,所以源码里放心用即可。
容易答错的地方
- 以为字符串里的下划线也能被解析
- 分隔符是词法层面的语法,只在源码的数字字面量里有效。从输入框、URL 参数、JSON 里拿到的
'1_000'是普通字符串,Number会返回NaN。要支持这种输入,得先用replace(/_/g, '')去掉下划线再转换。 - 以为只能用在十进制整数里
- 很多人只记得
1_000_000这种写法。实际上二进制、八进制、十六进制、BigInt 都能用,小数部分和指数部分也能用,比如1e1_0就是 10 的 10 次方。限制在于位置,不在于字面量类型。 - 把它和千分位格式化混为一谈
- 分隔符不影响输出。要在页面上显示
1,000,000,用的是toLocaleString()或Intl.NumberFormat,和源码里写不写下划线没有关系。
面试官还会怎么问?
为什么选下划线,不用逗号或空格?
逗号在 JavaScript 里已经是逗号运算符和参数分隔符,f(1,000) 会被当成两个参数。空格会把一个 token 拆成两个。下划线不会和现有语法冲突,而且 Java、Python、Rust 等语言早就用下划线做数字分隔符,开发者比较熟悉。
JSON 里能用数字分隔符吗?
不能。JSON 的数字格式是独立规范,比 JavaScript 字面量严格得多,不支持下划线,也不支持十六进制、前导 0 和末尾的小数点。JSON.parse('1_000') 会直接抛 SyntaxError。
TypeScript 里能用吗?
可以。TypeScript 从 2.7 开始支持数字分隔符,编译目标低于 ES2021 时会把下划线去掉再输出。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。