toFixed方法的bug

最近在工作过程中碰到一个隐藏的bug,经调试发现竟然是toFixed函数不可靠的结果引起的。后端同学在处理价格比较的时候,用foFixed进行价格的四舍五入之后,竟然发现比较的结果有问题;

大家都知道,Number类型的变量有个toFixed方法,该方法将Number四舍五入为指定小数位数的数字,以字符串返回。

IE:

1
2
0.6 .toFixed(0); // 0
1.6 .toFixed(0); // 2

Chrome:

1
2
0.6 .toFixed(0); // 1
1.6 .toFixed(0); // 2

另外还发现,就算是同在Chrome里,四舍五入也不靠谱:

1
2
( 0.035 ).toFixed( 2 ); // 0.04
( 0.045 ).toFixed( 2 ); // 0.04

这次IE倒是靠谱了:

1
2
( 0.035 ).toFixed( 2 ); // 0.04
( 0.045 ).toFixed( 2 ); // 0.05

结论 :toFixed()函数靠不住,如果有需要精确控制的情况,还是自己写个方法比较好。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
function toFixed(number, decimal) {
    decimal = decimal || 0;
    var s = String(number);
    var decimalIndex = s.indexOf('.');
    if (decimalIndex < 0) {
        var fraction = '';
        for (var i = 0; i < decimal; i++) {
            fraction += '0';
        }
        return s + '.' + fraction;
    }
    var numDigits = s.length - 1 - decimalIndex;
    if (numDigits <= decimal) {
        var fraction = '';
        for (var i = 0; i < decimal - numDigits; i++) {
            fraction += '0';
        }
        return s + fraction;
    }
    var digits = s.split('');
    var pos = decimalIndex + decimal;
    var roundDigit = digits[pos + 1];
    if (roundDigit > 4) {
        //跳过小数点
        if (pos == decimalIndex) {
            --pos;
        }
        digits[pos] = Number(digits[pos] || 0) + 1;
        //循环进位
        while (digits[pos] == 10) {
            digits[pos] = 0;
            --pos;
            if (pos == decimalIndex) {
                --pos;
            }
            digits[pos] = Number(digits[pos] || 0) + 1;
        }
    }
    //避免包含末尾的.符号
    if (decimal == 0) {
        decimal--;
    }
    return digits.slice(0, decimalIndex + decimal + 1).join('');
}
var a = 19.02
var b = 209.01
// 结果
console.log(toFixed(a, 2)); //==> 19.02
console.log(toFixed(b, 2)); //==> 209.01
console.log(Number(toFixed(a, 2)) < Number(toFixed(b, 2))); //==> true
posted @   Jone_chen  阅读(4014)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示