JavaScript大数运算需绕开Number精度缺陷,优先用BigInt处理整数,decimal.js处理小数,字符串算法作轻量备选,并实施全链路类型守卫。

JavaScript 中处理大数运算,核心是绕开 Number 类型的固有缺陷——它用 IEEE 754 双精度浮点表示,整数安全上限仅为 Number.MAX_SAFE_INTEGER(9007199254740991),超过就会丢精度;小数则天然存在二进制表示误差。金融、ID、时间戳纳秒等场景必须主动防御,不能靠“差不多”。
用 BigInt 处理超大整数(推荐首选)
BigInt 是原生类型,专为任意精度整数设计,后缀加 n 或用 BigInt() 构造。它不支持小数,但正适合“分”“个”“纳秒”这类整数单位。
- 金额统一用“分”存:比如
"12345678901234567890"分(约 1234 亿元),必须写成BigInt("12345678901234567890"),不能用Number解析 - 运算全程保持 BigInt:加减乘除取模都用
100n、amountInCents % 100n等形式,禁止混用100(会报错或隐式转换失效) - 解析 JSON 时拦截字符串:标准
JSON.parse()会把大数字字符串转成失真的Number,需用reviver主动识别并升为 BigInt,例如:JSON.parse(jsonStr, (k, v) => typeof v === 'string' && /^\d+$/.test(v) ? BigInt(v) : v) - 序列化前转回字符串:BigInt 不能被
JSON.stringify()直接处理,需用replacer或手动调.toString()
用 decimal.js / bignumber.js 处理带小数的大数
BigInt 不支持小数,而金融展示常需“元”(如 123456789.01),这时必须用高精度十进制库。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
decimal.js和bignumber.js都基于字符串实现,可精确控制小数位、四舍五入模式,且兼容Math常用方法(如sqrt、pow) - 创建实例时传字符串:
new Decimal("9007199254740991000000.123456789"),避免从 Number 初始化引入误差 - 所有运算返回新实例:
dec1.plus(dec2).times("1.05"),链式调用清晰,结果用.toString()输出供展示或传输 - 注意内存与性能:对海量高频计算,需合理设置精度(
Decimal.set({ precision: 20 })),避免过度保留位数拖慢速度
手写字符串算法(轻量/无依赖场景)
当项目不允许引入第三方库,且只涉及加减法等基础运算时,可用字符串模拟竖式计算,完全规避类型限制。
立即学习“Java免费学习笔记(深入)”;
- 从末位开始逐位相加,维护进位变量,拼接结果字符串
- 需统一补零对齐长度,处理前置零(如
"00123"→"123") - 适用于订单号拼接、简单求和等确定性低频操作,但乘除开方等复杂运算实现成本高、易出错,不建议自行封装
- 示例关键逻辑:
while (i >= 0 || j >= 0 || carry) { const sum = (digitA || 0) + (digitB || 0) + carry; result = (sum % 10) + result; carry = Math.floor(sum / 10); }
统一单位 + 全链路类型守卫
精度问题从来不是单点故障,而是“接收→运算→传输”三环脱节的结果。
- 后端接口约定:大整数字段(金额分、订单ID、纳秒时间戳)一律返回字符串,语义明确,前端无需猜类型
- 前端存储与运算:金额字段在 state 或 class 属性中始终为 BigInt 或 Decimal 实例,绝不存 Number
- 展示层分离:运算用整数,显示转“元”时再做格式化,例如
`${(amountInCents / 100n).toString()}.${(amountInCents % 100n).toString().padStart(2,'0')}` - 边界校验:关键操作前检查值是否在
Number.MAX_SAFE_INTEGER内,仅对确认安全的值才转Number(如图表坐标、非金融计数)

















