谨慎使用JavaScript中的toFixed方法

最近做相关报表的时候,测试小伙伴反馈导出的数据和前端页面显示的数据不对,并且经过对比发现是我的页面的数据进位有问题。之前接手项目的时候这个逻辑不是我维护的,结果排查了一下代码之后,发现了一个很有趣的问题,这里记录一下。

PS:其实这也是前端开发一个老生常谈的问题了,高手可以直接跳过啦。

问题再现

直接在在浏览器里运行如下代码:

发现了问题了没?这并不是一个标准的四舍五入。

PS:上述在代码在IE、FireFox、Chrome下运行结果还可能不一致。

银行家舍入算法?

看了不少文档说,JavaScript的文档使用的是银行家舍入算法,我感觉这篇文章《银行家舍入法 - 简书》写的比较好。

简单来说就是:

四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

但如果你仔细求证会发现Chrome中并不一定都符合这个算法。

ECMA规范

具体我们还是来看ECMA的规范吧:《ECMAScript 2015 Language Specification – ECMA-262 6th Edition

具体算法如下:

中文版

「修复」toFixed

查了一下项目中之前有不少地方都是使用的toFixed方法,后续开发使用的lodash的round方法已经避免了这个问题。当然可以使用round方法来替换toFixed方法,但工作量比较大,比较直接的方法直接重写toFixed方法。

1Number.prototype.toFixed = function(decimals) {
2  return Math.round(this * Math.pow(10, decimals)) / (Math.pow(10, decimals));
3};

参考

  1. 『前端BUG』—— toFixed四舍五入的不准确性 - 掘金
  2. ECMAScript 2015 Language Specification – ECMA-262 6th Edition
  3. 银行家舍入法 - 简书