BigInt S4
中文标题:BigInt:JavaScript 中的任意精度整数
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2020
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案引入了 BigInt,这是一种新的原始类型,用于表示超出 JavaScript 安全整数限制(2^53)的任意大整数。它定义了语法、运算符、比较以及与其他类型的交互,并讨论了陷阱和设计目标。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
BigInt:JavaScript 中的任意精度整数
Daniel Ehrenberg, Igalia。阶段 4
此提案已完成并已合并到 ECMA262 规范中。参见规范文本此处。
感谢 Brendan Eich、Waldemar Horwat、Jaro Sevcik、Benedikt Meurer、Michael Saboff、Adam Klein、Sarah Groff-Palermo 等人对这项工作的帮助和反馈。
目录
它是什么?
BigInt 是一种新的原始类型,提供了一种表示大于 253 的整数的方法,253 是 JavaScript 用 Number 原始类型能够可靠表示的最大数字。
在 Daniel 在 JSConfEU 的演讲幻灯片中了解更多关于 JavaScript 中数字表示方式的信息。
它如何工作?
以下部分展示了 BigInt 的实际应用。其中许多内容受到 Mathias Bynens 的 BigInt V8 更新 的影响或直接取自该更新,该更新包含比本页更多的细节。
语法
通过在整数末尾追加 n 或调用构造函数来创建 BigInt。
示例:计算质数
运算符
你可以对 BigInt 使用 +、*、-、** 和 %,就像对 Number 一样。
/ 运算符也按预期适用于整数。然而,由于这些是 BigInt 而不是 BigDecimal,此操作将向零舍入,也就是说,它不会返回任何小数位。
比较
BigInt 与 Number 不严格相等,但宽松相等。
Number 和 BigInt 可以像往常一样进行比较。
它们可以混合在数组中并排序。
条件
BigInt 在转换为 Boolean 时(如 if、||、&&、Boolean、!)的行为类似于 Number。
其他 API 说明
BigInt 也可以用于 BigInt64Array 和 BigUint64Array 类型化数组 中以表示 64 位整数。
陷阱与异常
与 Number 和 String 的互操作
最大的意外可能是 BigInt 不能与 Number 互换操作。相反,会抛出 TypeError。(阅读设计哲学了解更多关于为什么做出这个决定的原因。)
BigInt 也不能使用一元 + 转换为 Number。必须使用 Number。
但是,BigInt 可以 与字符串连接。
因此,建议对于只会遇到小于 253 的值的代码,继续使用 Number。
将 BigInt 保留用于预期出现大值的情况。否则,通过来回转换,你可能会失去你想要保留的精确性。
将 Number 值保留用于它们为不大于 253 的整数的情况,对于其他情况,建议使用字符串(或 BigInt 字面量)以避免精度损失。
舍入
如上所述,BigInt 仅表示整数。Number 仅能可靠地表示不超过 253 的整数。这意味着除法和转换为 Number 都可能导致舍入。
密码学
BigInt 上支持的操作不是常数时间的。因此,BigInt 不适合用于密码学。
许多平台提供对密码学的原生支持,例如 webcrypto 或 node crypto。
其他异常
尝试将小数值转换为 BigInt 时,无论该值表示为 Number 还是 String,都会抛出异常。
Math 库中的操作在与 BigInt 一起使用时将抛出错误,| 运算符也是如此。
但是,parseInt 和 parseFloat 会将 BigInt 转换为 Number 并在此过程中丢失精度。(这是因为这些函数会丢弃尾随的非数字值——包括 n。)
最后,BigInt 不能序列化为 JSON。但是,有一些库——例如 granola——可以为你处理这个问题。
使用建议
强制转换
由于在 Number 和 BigInt 之间强制转换可能导致精度损失,因此建议仅在合理预期会出现大于 253 的值时使用 BigInt,并且不要在这两种类型之间进行强制转换。
关于此提案
动机:为什么我们需要如此大的数字?
在 JavaScript 编码中,有几种情况会出现大于 253 的整数——既包括需要有符号或无符号 64 位整数的情况,也包括可能希望使用大于 64 位的整数的情况。
64 位使用案例
通常,与 JavaScript 交互的其他系统以 64 位整数提供数据,这些数据在转换为 JavaScript Numbers 时会丢失精度。
这些可能出现在读取某些机器寄存器或线路协议、使用包含由 64 位系统生成的 GUID 的 protobuf 或 JSON 文档时——包括信用卡号或账号等——目前这些在 JavaScript 中必须保持为字符串。(注意,BigInt 不能直接序列化为 JSON。但你可以使用诸如 granola 之类的库将 BigInt 和其他 JS 数据类型序列化和反序列化为 JSON。)
在 node 中,fs.stat 可能会以 64 位整数提供一些数据,这已经引起了问题:
最后,64 位整数支持更高分辨率——纳秒!——的时间戳。这些将在时间提案中使用,该提案目前处于 Stage 1。
大于 64 位的使用案例
大于 64 位的整数最有可能在进行大型整数数学计算时出现,例如解决 Project Euler 问题或精确几何计算。添加 BigInt 使得满足用户对高级语言整数运算“正确”且不会突然溢出的合理期望成为可能。
如果这看起来牵强,可以考虑奔腾 FDIV bug 的情况。1994 年,奔腾芯片中的一个 bug 使得浮点值很少——但可能——不精确。它被一位依赖该精度的数学教授发现。
设计目标,或为什么这样设计?
以下原则指导了本提案所做的决策。查看 ADVANCED.md 以获取每个原则的更深入讨论。
在维护用户直觉和保持精度之间找到平衡
总的来说,本提案旨在以与用户对 JavaScript 工作方式的直觉互补的方式工作。同时,本提案的目标是为语言增加进一步的精度支持。有时这些可能会冲突。
当出现混乱情况时,本提案倾向于抛出异常,而不是依赖类型强制转换并冒险给出不精确的答案。这就是在将 BigInt 和 Number 相加以及其他上述异常时抛出 TypeError 的原因:如果我们没有好的答案,最好不给答案。
有关这些选择的更多讨论,请参见 Axel Rauschmeyer 的提案 和 关于其对 Numbers 影响的进一步讨论。我们最终得出结论,提供 Number 和 BigInt 之间的透明互操作是不切实际的。
不破坏数学
所有运算符的语义理想情况下应基于某种数学第一性原理,以匹配开发者的期望。除法和取模运算符基于其他编程语言中整数的约定。
不破坏 JavaScript 的易用性
本提案带有内置的运算符重载,以避免 BigInt 变得过于丑陋而难以使用。一个特别的危险是,如果要使用静态方法操作 BigInts,用户可能会将 BigInt 转换为 Number 以便对其使用 + 运算符——这在大多数情况下都能工作,但值不够大时可能失败,因此可能通过测试。通过包含运算符重载,正确地将 BigInts 相加比将它们转换为 Numbers 更短,从而最大限度地减少此 bug 的发生机会。
不破坏 Web
本提案不会改变 Numbers 的工作方式。选择 BigInt 这个名字部分是为了避免更通用的 Integer 名称带来的兼容性风险(部分是为了明确它们对于“大”的情况有用)。
不破坏良好性能
这里的设计工作与原型实现相结合,以确保提案可以高效实现。
不破坏未来潜在的值类型扩展
在向语言添加新原始类型时,重要的是避免赋予它们难以泛化的超级能力。这是 BigInt 避免混合操作数的另一个好理由。
然而,混合比较是这个原则的一次性例外,是为了支持直觉设计原则。
不破坏 JavaScript 的一致模型
本提案添加了一种新的原始类型及其包装器,类似于 Symbol。作为将 BigInts 集成到 JavaScript 规范中的一部分,需要高度严谨地区分规范中出现的三种类型:数学值、BigInt 和 Number。
提案状态
此提案目前处于 Stage 4。
BigInt 已在 Chrome、Node、Firefox 中发布,并在 Safari 中推进中。
- V8 由 Georg Neis 和 Jakob Kummerow 完成。
- JSC 由 Caio Lima 和 Robin Morisset 完成。
- SpiderMonkey 由 Robin Templeton 和 Andy Wingo 完成。
相关规范提案: