大整数为什么丢失精度?MAX_SAFE_INTEGER、MAX_VALUE 与 BigInt 怎么选?
先理解原理和示例,再练习完整口述与追问。
回答要点
安全整数上限为 2^53−1;有限量级上限与精度无关;ID 用字符串;整数运算用 BigInt;JSON 序列化显式约定。
原理拆解
JavaScript Number 使用 IEEE 754 双精度浮点数。Number.MAX_SAFE_INTEGER 是 9007199254740991,即 2^53−1,超过这个范围就不能保证每一个整数都能被精确表示和区分。Number.MAX_VALUE 大约是 1.7976931348623157e308,表示最大有限正数的量级,它并不意味着这个范围内的整数都有精确个位。
订单号、雪花 ID 之类不参与算术的标识应由后端直接以字符串返回。若 JSON 中已经把超大 ID 写成普通数字,JSON.parse 可能在解析时就丢失精度,之后再 String 或 BigInt 都无法恢复原值。需要精确整数运算时,从字符串或带 n 的字面量创建 BigInt,例如 BigInt('9007199254740993');BigInt 除法向零截断,不能表示小数,不能与 Number 直接混合算术,转回 Number 前需要检查范围。
默认 JSON.stringify 无法直接序列化 BigInt,会抛 TypeError。接口一般约定大整数编码成十进制字符串;若使用 replacer 转字符串,接收端仍需依据字段协议恢复,不能把所有数字字符串都自动当 BigInt。金额运算还要定义最小货币单位、舍入规则与边界,不能仅把任意浮点金额交给 BigInt。
示例与推演
const id = '9007199254740993'
console.log(BigInt(id) + 1n) // 9007199254740994n
console.log(Number(id) === Number('9007199254740992')) // true
console.log(JSON.stringify({ id })) // ID 保持字符串
后两个不同文本一旦转为 Number 已经无法区分;BigInt(Number(id)) 也只能得到已舍入数值对应的整数。
易错点
大整数 ID 最好在接口源头就编码为字符串。BigInt 可精确表示整数,但不提供小数金额的自动舍入策略。
参考回答可直接练习口述
JavaScript Number 使用 IEEE 754 双精度浮点数。Number.MAX_SAFE_INTEGER 是 9007199254740991,即 2^53−1,超过这个范围就不能保证每一个整数都能被精确表示和区分。Number.MAX_VALUE 大约是 1.7976931348623157e308,表示最大有限正数的量级,它并不意味着这个范围内的整数都有精确个位。