Number.MAX_SAFE_INTEGER 为 9007199254740991(2⁵³−1),是 JavaScript 中能精确表示的最大安全整数;超出后因 IEEE 754 双精度浮点数尾数仅 53 位有效精度,导致整数丢失。

JavaScript 中的 Number.MAX_SAFE_INTEGER 是一个关键常量,它定义了“安全整数”的上限:即 9007199254740991(2⁵³ − 1)。超过这个值,JavaScript 的 Number 类型(基于 IEEE 754 双精度浮点格式)就无法**精确表示每一个整数**,从而引发隐式精度丢失——这不是 Bug,而是浮点数表示机制的固有局限。
为什么是 2⁵³?——浮点数存储原理简析
IEEE 754 双精度数使用 64 位:1 位符号 + 11 位指数 + 52 位尾数(mantissa)。虽然尾数只有 52 位,但规范规定隐含一个前导 1,因此实际可提供 **53 位有效二进制精度**。这意味着:在 [0, 2⁵³) 区间内,每个整数都能被唯一、精确地表示;一旦 ≥ 2⁵³,相邻可表示数之间的间隔变为 2 或更大,中间的整数就会“消失”。
- 例如:
9007199254740991 + 1 === 9007199254740992✅(安全) - 而:
9007199254740992 + 1 === 9007199254740992❌(+1 被舍入丢弃) -
Number.isSafeInteger(9007199254740992)返回false
哪些场景容易踩坑?
精度问题常在不经意间暴露:
- ID 处理:后端返回的 64 位整数 ID(如 MongoDB ObjectId 时间戳部分、Snowflake ID)可能远超 MAX_SAFE_INTEGER,直接赋值给 JS Number 会失真
- 大金额计算:以“分”为单位处理万元级金额(如 100000000 分 = 100 万元),数值达 1e8,虽仍在安全范围内;但若涉及更高精度或累加误差,仍需警惕
- 数组索引与 length:数组最大长度理论为 2⁵³−1,但实际引擎限制更严(如 V8 约 2³²−1),且超大索引会触发稀疏数组行为
- JSON 解析:JSON 本身无类型,数字一律按 double 解析;若原始 JSON 含超安全范围整数,JS 解析后即已失真
如何正确处理超安全整数?
核心原则:**避免用 Number 存储和运算超范围整数**。
立即学习“Java免费学习笔记(深入)”;
-
字符串优先:对 ID、序列号等只做传输/展示的整数,全程保持字符串类型(
"90071992547409911"),避免解析成 Number -
BigInt 使用:ES2020 引入
BigInt(字面量加n,如9007199254740991n),支持任意精度整数运算。注意:BigInt 不能与 Number 混合运算,且不兼容 JSON -
专用库辅助:如
big-integer、bignumber.js提供字符串/number 输入、高精度运算及序列化能力,适合金融等强精度场景 -
服务端协同:API 设计时,对超长整数字段明确约定为字符串类型(Swagger 中设
type: string,format: int64),前端不自行转换
快速检测与防护建议
运行时可用原生 API 主动防御:
-
Number.isSafeInteger(value):判断是否为安全整数(同时检查是否为 number 类型且在范围内) -
Number.MAX_SAFE_INTEGER与Number.MIN_SAFE_INTEGER(−2⁵³+1)可作边界比对 - 开发阶段启用 ESLint 规则
no-loss-of-precision,自动拦截90071992547409911这类字面量误用 - 对用户输入或 API 响应中的数字字段,增加校验逻辑(如正则匹配纯数字字符串后判断长度 > 16 则转 BigInt 或告警)


















