结算页算运费,0.1 + 0.2 打印出来是 0.30000000000000004,调了 toFixed(2) 显示 0.30 看着正常,可换成 1.005 就变成 1.00,财务对账直接差一分钱。js tofixed 看着简单,坑全在细节里。
它返回的是字符串
(1.234).toFixed(2) 得到 '1.23',typeof 是 string。后面还要参与计算,得先 Number() 转回来,或者前面加个加号转。+'1.23' 这种写法短,但别在复杂表达式里用,容易看晕。保留几位就传几,传 0 就是取整,传超过 100 会抛 RangeError。
为什么 1.005 会被舍成 1.00
十进制小数在二进制里大多存不精确,1.005 实际存的值大约是 1.00499999999999989,toFixed 按这个值四舍五入,自然进不上去。2.55 保留一位得到 2.5 也是同一个原因。这不是浏览器 bug,是浮点数的老毛病。
算钱先换成整数
常见做法是元变分,Math.round(price * 100) 之后加减都在整数上做,展示时再除以 100。要求更严格就引入 decimal.js 这类库,链式调用加乘减,再格式化。订单金额、发票金额这种场景,别省这一步。
四舍五入和截断要分清
toFixed 做的是四舍五入,(1.239).toFixed(2) 是 1.24。真想直接砍掉后面的位数,用 Math.floor(n * 100) / 100。负数注意方向,floor 对 -1.239 得到 -1.24,跟直觉相反。
只做展示的话还有个替代方案:Intl.NumberFormat('zh-CN', { minimumFractionDigits: 2 }),自带千分位,适合商品价格这类展示位。它同样受浮点误差影响,不能拿来做计算。
说到底,js tofixed 只是格式化工具,不是计算工具。展示前格式化,计算用整数或专用库,账目就不会差那一分钱。另外不同浏览器引擎对极端值的处理有细微差别,发版前在目标浏览器上跑一遍。