JavaScript数字均为IEEE 754双精度浮点数,导致0.1+0.2≠0.3、整数超MAX_SAFE_INTEGER失真、NaN不等于自身;字符串转数字需慎用隐式转换,推荐Number()或显式parseInt(str,10);比较小数应取绝对差值阈值而非===。

JavaScript 中的数字运算看似简单,但实际开发中常因类型隐式转换、浮点精度、边界值等问题引发意外行为。直接用 + 拼字符串、0.1 + 0.2 === 0.3 返回 false、parseInt("08") 返回 0——这些都不是“bug”,而是规则没吃透。
数字类型只有一种:Number,但表现很复杂
JS 没有 int、float 分离,所有数字都是 IEEE 754 双精度 64 位浮点数。这意味着:
-
Number.MAX_SAFE_INTEGER是9007199254740991,超过这个值后整数可能丢失精度(比如9007199254740992 + 1仍等于9007199254740992) - 小数运算不精确:
0.1 + 0.2得到0.30000000000000004,不是四舍五入问题,是二进制无法精确表示十进制小数 -
typeof NaN是"number",NaN === NaN为false,判断必须用isNaN()或更安全的Number.isNaN()
字符串转数字:别只靠 + 和 parseInt
隐式转换容易踩坑,比如 +"0x10" 得 16,+"08" 在非严格模式下可能被当八进制(已废弃但旧环境仍有影响);parseInt("123abc") 返回 123,而 Number("123abc") 返回 NaN。
- 想严格转整数:用
Number.parseInt(str, 10),显式指定进制,避免老版本把前导0当八进制 - 想转浮点数:优先用
Number(str),它对空格、前后空白更敏感(Number(" 42 ")→42,Number("42.5.6")→NaN) - 想快速转数字且容忍宽松:一元加号
+str最简,但+" "是0,+"abc"是NaN,需自行校验
浮点数比较和取整:绕不开的精度与舍入策略
直接用 === 比较小数几乎总是错的;Math.round() 对 .5 的处理是“向偶数舍入”(banker’s rounding),比如 Math.round(1.5) 和 Math.round(2.5) 都返回 2。
立即学习“Java免费学习笔记(深入)”;
- 比较小数是否相等:用差值绝对值小于阈值,例如
Math.abs(a - b) (EPSILON ≈ 2.22e-16) - 需要固定小数位并四舍五入:用
parseFloat(num.toFixed(2)),注意toFixed()返回字符串,且在某些浏览器对负数处理不一致 - 需要截断而非四舍五入:用
Math.trunc()(ES6),比Math.floor()更适合负数(Math.trunc(-3.7)→-3,Math.floor(-3.7)→-4)
大整数运算:超出 SAFE_INTEGER 怎么办
如果涉及 ID、时间戳、加密计算或金融大额整数,Number 类型会悄悄出错。此时不能硬扛,得换方案。
- 纯整数大数运算:用
BigInt,写法是末尾加n(123n)或调用BigInt("123");注意BigInt不能和Number混用(1n + 2报错) - 高精度小数(如金额):推荐用字符串 + 专用库(如
decimal.js或big.js),避免自己实现乘除逻辑 - 时间戳毫秒值:现代浏览器中
Date.now()返回的数字在 2038 年前仍是安全的,但若做毫秒级差值累加,长期运行仍可能越界,建议用BigInt(Date.now())预留余量
真正麻烦的从来不是“怎么算”,而是“怎么知道它算对了”。尤其在表单输入、金额展示、数据聚合这些地方,一个没兜住的 parseInt 或一次没校验的 +,可能让前端显示和后端存储差出几倍。数值处理没有银弹,只有根据场景选对工具,并始终检查边界和类型。











