← 返回题目列表

BigInt 解决了什么问题?使用时有哪些限制?

高频 中等 第 8 / 28 题 更新于 2026/07/28
ES2020BigInt数字精度

简化版

BigInt 用来表示超过 Number.MAX_SAFE_INTEGER 的整数,避免大整数精度丢失;它通过 123nBigInt() 创建,但不能和普通 Number 直接混算,也不能表示小数。

详细版

JavaScript 的 Number 使用双精度浮点数,安全整数范围是 -(2^53 - 1)2^53 - 1。 超过这个范围后,整数运算可能不再精确。

Number.MAX_SAFE_INTEGER; // 9007199254740991
9007199254740991 + 1;   // 9007199254740992
9007199254740991 + 2;   // 9007199254740992

BigInt 可以表达任意大的整数:

const id = 9007199254740993n;

面试重点:它解决大整数精度,不解决小数精度;不能和 Number 随意混算;JSON 序列化要特别处理。

完整版教学

一、Number 的安全整数边界从哪里来

JavaScript 的普通数字是 IEEE 754 双精度浮点数。 它能表示很大的范围,但不是每个整数都能精确表示。 安全整数上限是 2^53 - 1,也就是 9007199254740991

MAX_SAFE_INTEGER = 2^53 - 1
                 = 9007199254740991

超过这个范围后,相邻整数可能映射到同一个 Number。 这就是为什么 9007199254740991 + 1+ 2 可能得到相同结果。 对于订单号、雪花 ID、数据库长整型主键,这会造成严重问题。

二、BigInt 专门表示任意精度整数

BigInt 用 n 后缀或 BigInt() 创建。 它不是 Number 的增强模式,而是一个新的原始类型。 typeof 1n 的结果是 "bigint"

const a = 123n;
const b = BigInt('9007199254740993');

console.log(typeof a); // "bigint"
console.log(b + 1n);   // 9007199254740994n

如果有 19 位订单号,用 Number 接收可能丢精度。 用字符串传输、进入 JS 后按需转成 BigInt,通常更稳妥。

三、BigInt 不能和 Number 直接混合运算

BigInt 和 Number 表达的是不同数字系统。 直接混合加减乘除会抛出 TypeError。 这样设计是为了避免隐式转换带来的精度损失。

1n + 2; // TypeError
1n + BigInt(2); // 3n
Number(1n) + 2; // 3
操作结果风险
1n + 2报错禁止隐式混算
1n + 2n3n保持整数精度
Number(big)Number可能丢精度
BigInt(num)BigIntnum 不能是小数

转换方向要看业务。 如果值可能超过安全整数,应尽量保留 BigInt 或字符串,不要转回 Number。

四、BigInt 只能表示整数,不能处理小数精度

BigInt 不是金融小数方案。 它不能表示 1.5n,也不能直接处理 0.1 + 0.2 的浮点误差。 如果要处理金额,常见做法是用整数分单位或使用十进制定点库。

// 错误
// const x = 1.5n;

const cents = 1999n; // 19.99 元用分表示

数字例子:19.99 元可以存成 1999 分。 用 BigInt 可以让特别大的金额整数部分保持精度,但小数位规则仍要由业务定义。

五、JSON 和接口传输要特别注意

JSON.stringify 默认不能直接序列化 BigInt。 这在前后端接口、日志上报、本地缓存中都很常见。 通常会把 BigInt 转成字符串传输。

const data = { id: 9007199254740993n };

JSON.stringify(data); // TypeError

JSON.stringify(data, (_, value) =>
  typeof value === 'bigint' ? value.toString() : value
);

流程建议:

后端 long / bigint
  -> JSON 中用字符串
  -> 前端展示直接用字符串
  -> 需要整数运算时转 BigInt

这能避免进入 JS Number 后已经丢精度。

六、比较、排序和工程边界

BigInt 可以和 Number 做宽松相等或大小比较,但不建议依赖复杂隐式规则。 排序时尤其要小心,不要写 a - b,因为减法会混合运算。 更稳妥的写法是返回 -1/0/1

const list = [3n, 1n, 2n];
list.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));

记忆钩子:BigInt 是大整数保险箱,不是所有数字问题的万能药。

工程中最常见的建议是:ID 类字段不要用 Number 接。 展示用字符串,计算用 BigInt,涉及小数用定点方案。

七、常见误区与追问

  • 误区:BigInt 可以解决 0.1 + 0.2 问题。 BigInt 只能表示整数,小数精度要用定点或十进制库处理。
  • 误区:后端 long 到前端直接用 Number 没问题。 超过安全整数后可能丢精度,ID 应优先按字符串传输。
  • 误区:BigInt 能和 Number 自动相加。 直接混合运算会报错,需要显式转换。
  • 追问:为什么 BigInt 不能直接 JSON 序列化? JSON 标准没有 BigInt 数字类型,默认序列化会抛错。
  • 追问:Number.MAX_SAFE_INTEGER 是多少?9007199254740991,也就是 2^53 - 1
  • 追问:大整数排序为什么不能写 a - b 如果其中是 BigInt,减法结果也是 BigInt 或触发混算问题,排序函数应返回普通 Number 的比较结果。

八、加强记忆

BigInt 要抓住三个边界:它解决超过 2^53 - 1 的整数精度问题,不解决小数问题,不和 Number 隐式混算。前端遇到大 ID 时优先字符串传输和展示,确实要整数计算再转 BigInt。