作者:yanyige | 发布时间:2017-03-23 13:04

JS中toFixed()方法引起的精度丢失的问题解决

引子

某一天在JS初级前端开发群中潜水的时候,有一个同学提出了一个问题:”toFixed(2) 这个方法四舍五入有问题的 比如8.885.toFixed(2) 计算出来的是8.88不是8.89解决这个问题的办法只能是自己重写toFixed吗 谢谢”。我想了一下,如果是四舍五入的话8.885.toFixed(2)的结果的确应该为8.89,遂打开浏览器进行测试。

自我测试

打开chrome浏览器的控制台,输入如下代码:

>8.881.toFixed(2)
<"8.88"
>8.882.toFixed(2)
<"8.88"
>8.885.toFixed(2)
<"8.88"
>8.886.toFixed(2)
<"8.89"
>8.887.toFixed(2)
<"8.89"

的确,输入8.885保留二位小数的结果是8.88,也就是并没有四舍五入。我又进行了如下测试:

0.875.toFixed(2)
"0.88"
0.874.toFixed(2)
"0.87"
0.876.toFixed(2)
"0.88"

奇怪,测试数据为0.875的时候居然进位了!那就是说:在某些情况下toFixed()表现为四舍五入,有时候则是四舍六入,那么到底是怎么回事呢?

网上搜索

百度百科

toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。

网友

4舍6入5凑偶”这里“四”是指≤4 时舍去,”六”是指≥6时进上,”五”指的是根据5后面的数字来定,当5后有数时,舍5入1;当5后无有效数字时,需要分两种情况来讲:①5前为奇数,舍5入1;②5前为偶数,舍5不进。(0是最小的偶数)

事实上,经过测试你会发现,以上两种解释都是错误的。真实的情况是toFixed()方法在各浏览器下表现不一,浏览器JS库存在差异,所以表现不同。

解决办法

网上已经有很多解决方法,东抄抄西借借不是一个好的习惯。这里分享一下我的方法。

    Number.prototype.toFixed = function(n) {
        let temp = Math.pow(10, n);
        let part = (Math.round(this * temp) / temp + "").split('.');
        return part[1].length != n? part[0]+'.'+part[1]+Array(n-part[1].length + 1).join('0'): part[0]+'.'+part[1];
    }