JavaScript数字运算不准确是因为其Number类型基于IEEE 754双精度浮点数,无法精确表示多数十进制小数,如0.1+0.2≠0.3;应对需分场景:金额用整数运算,科学计算用BigInt或decimal.js,显示用Number(toFixed()),比较用误差容忍。
因为 JavaScript 只有一种数字类型 Number,底层用 IEEE 754 双精度浮点数表示,0.1 + 0.2 !== 0.3 就是典型表现。这不是 bug,而是二进制无法精确表示大多数十进制小数导致的固有局限。
不能一概用 toFixed() 或 Math.round() 修显示——它们返回字符串或四舍五入后丢失原始精度,且对负数、边界值处理不一致。关键看场景:
BigInt(仅整数)或第三方库如 decimal.js、big.js
Number(val.toFixed(n)) 转回数字,而非直接用 toFixed() 结果参与后续计算Math.abs(a - b)
Number.EPSILON 是什么?怎么用?Number.EPSILON 是 1 与大于 1 的最小可表示数之间的差值(约 2.220446049250313e-16),它不是“通用精度阈值”,只适用于 1 附近的数。比较两个数是否相等,应按数量级缩放误差:
function numbersEqual(a, b) {
if (a === b) return true;
const diff = Math.abs(a - b);
const max = Math.max(Math.abs(a), Math.abs(b), 1);
return diff < Number.EPSILON * max;
}直接写 a === b 对整数安全;对小数比较,别硬套 Number.EPSILON,优先考虑业务容错范围(比如金额允许 ±0.01)。
精度损失?这些看似无害的操作实际都经过浮点路径:
parseFloat('0.1') → 得到的是近似值,不是精确 0.1JSON.parse('{"price": 19.99}') → 数字字段仍是浮点表示new Date(2025, 0, 1).getTime() / 1000 → 时间戳除法产生小数秒,精度不可靠0.1 + 0.2 === 0.30000000000000004 → 典型错误链起点真正可控的方式只有一种:从源头杜绝小数参与运算。比如后端传金额统一为整数分,前端不做 / 100 操作,直到最终渲染才格式化显示。