JavaScript 的 Number 类型基于 IEEE 754 双精度浮点格式,最大安全整数为 Number.MAX_SAFE_INTEGER(9007199254740991),超出此范围的整数在转换为 Number 时即发生精度丢失;BigInt 构造函数若接收已失真的 Number,无法恢复原始值,必须传入字符串才能保证精确性。
JavaScript 的 Number 类型遵循 IEEE 754 双精度浮点标准,其最大安全整数是 Number.MAX_SAFE_INTEGER,也就是 9007199254740991。一旦整数超过这个范围,在转换为 Number 的瞬间,精度就已经丢失了。而 BigInt 构造函数如果接收的是一个已经失真的 Number,即使内部再努力,也无法还原原始值——必须使用字符串来传递,才能确保精确无误。
举个例子,当你写下 BigInt(9223372036854775807) 时,看起来像是在传递一个精确的大整数,但真相是——这个数字在被 JavaScript 解析成 Number 的瞬间,精度就已经不复存在了。
问题出在 9223372036854775807 超过了 Number.MAX_SAFE_INTEGER,所以 JavaScript 引擎根本没法用 Number 精确表示它。来验证一下:
console.log(9223372036854775807); // 输出:9223372036854776000(已四舍五入!) console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991 console.log(9223372036854775807 === 9223372036854776000); // true
这样一来,9223372036854775807 这个字面量在 JS 里根本没法以 Number 的形式精确存在——它被自动近似成了 9223372036854776000。而 BigInt(9223372036854775807) 实际上等价于 BigInt(9223372036854776000),最终得到的 9223372036854775808n 自然也是错的(注意,BigInt 对 Number 输入会先转成整数再构造,但输入本身已经是一个错误值了)。
✅ 正确的做法是:始终用字符串来初始化 BigInt,这样就能绕过 Number 的精度瓶颈:
console.log(BigInt("9223372036854775807")); // 9223372036854775807n ✅
console.log(BigInt("9007199254740991") === 9007199254740991n); // true
console.log(BigInt("123456789012345678901234567890")); // 精确大整数
⚠️ 有几个注意事项需要留意:
- BigInt 构造函数不要接收 Number 类型的大整数字面量(尤其是超过 MAX_SAFE_INTEGER 的),否则一定会失真;
- 字符串里不能有空格、前导零(除非是 0o/0x/0b 进制前缀),且必须是纯整数格式;
- BigInt 和 Number 不能直接混在一起运算(比如 + 或 ==),需要显式转换(但 === 永远为 false,因为类型不同);
- 浏览器兼容性方面,现代浏览器都支持,但 IE 完全不支持,Node.js 需要 ≥ v10.4.0(旧版本得加上 --harmony-bigint 参数)。
总结一下:BigInt 的设计初衷是提供任意精度的整数运算,但它不负责修复上游 Number 的精度缺陷。要想保证精度,必须从源头阻断 Number 的解析——也就是用字符串字面量来创建 BigInt。这是 JavaScript 类型系统限制下的必然选择,而不是 API 用错了。
