以下为场景实测与原理分析,需要重写函数请直接滚动至页尾!!!

语法 - Number.prototype.toFixed( )

// toFixed()方法 使用定点表示法来格式化一个数值。
numObj.toFixed(digits)
参数 描述
digits 小数点后数字的个数;介于 0 到 20 (包括)之间,实现环境可能支持更大范围。如果忽略该参数,则默认为 0。

MDN给出的实例

function financial(x) {
return Number.parseFloat(x).toFixed(2);
} console.log(financial(123.456));
// expected output: "123.46" console.log(financial(0.004));
// expected output: "0.00" console.log(financial('1.23e+5'));
// expected output: "123000.00"

然而事实浏览器反馈给我们的结果并非如此。

找到原因

经阅读 .toFixed()为什么精度损失js中toFixed精度问题的原因及解决办法 两篇文章得到了相对可靠的解释:

toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。例如将数据Num保留2位小数,则表示为:toFixed(Num);但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:简单来说就是:四舍六入五考虑,五后非零就进,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

实际场景(多浏览器实测)

  1. Chrome

   

   可以发现在chorme下没有完全去遵循这个规律,看来Chrome有自己的算法,测试1.305 ~ 1.395十个用例,得:在Chrome浏览器中toFixed()的后一位 >6时进位,否则舍去。

   2.IE 版本11

   

   IE同样没有采纳银行家舍入法,但所有实例都通过了四舍五入的测试。

   3.EDGE

   

   4.FireFox

   

   5.Opera

   

   6.PC Weixin内置浏览器

   

   7.QQ浏览器

   

   在QQ浏览器的智能、极速、IE三个内核模式切换,得到的都是同上大部分的结果。

结论

除了IE11浏览器外,大部分主流浏览器num.toFixed(2)采用了:

num的百分位小数 > 6 ? ( 千分位小数 > 4 ? 进位 : 舍去 ) : 无差别舍去

IE11浏览器则是全部通过四舍五入思维,我无法保证上述文章提到的银行家舍入法一定是误判,但目前精度丢失的规律已经明了。

重写toFixed()

解决方法也非常简单,重写Number.prototype.toFixed()方法(补零无效):

Number.prototype.toFixed = function (s) {
changenum = (parseInt(this * Math.pow( 10, s ) + 0.5) / Math.pow( 10, s )).toString()
return changenum;
}

理念是将小数点左移s(参数)个单位,加上0.5后取整完成四舍五入,如 1.236.toFixed(2) 小数点左移两个单位 -> 123.6 + 0.5 = 124.1 取整 -> 124,最后再将小数点右移s个单位后将Float类型格式化为String类型后return即可。

该方法存在一个问题,即假设参数大于浮点数长度,1.23.toFixed(3) 运算过程 -> 1230 -> 1230.5 -> 1230 -> 1.23,此处的 + 0.5 完全是无效的,且理想结果应补零至千分位得到 1.230 ,优化该方法(可用最终版):

/***************************************************************************
* Number.prototype.toFixed() -> rewrite *
***************************************************************************/
Number.prototype.toFixed = function (s) {
changenum = (parseInt(this * Math.pow( 10, s ) + 0.5) / Math.pow( 10, s )).toString()
index = changenum.indexOf(".")
if(index < 0 && s > 0){
changenum = changenum+"."
for(i = 0; i < s; i++){
changenum = changenum + "0"
}
} else {
index = changenum.length - index;
for(i = 0; i < (s - index) + 1; i++){
changenum = changenum + "0"
}
}
return changenum;
}

进阶 - Number.prototype消失的 “ 0 ”

在所有浏览器下,String("0.050").toFixed(2) = 0.1

原本保留至百分位的小数只保留到了十分位,并非是toFixed( )舍弃了最后的 “ 0 ”,而幕后黑手是Number.prototype,所有toFixed、toString这样的对象方法都成了它的背锅侠。

这个坑留到以后再填

最新文章

  1. QML 从无到有 2 (移动适配)
  2. jQuery ajax的traditional参数的作用///////////////////////////////////zzzzzzzzzzz
  3. 基于.NET平台常用的框架整理【转】
  4. 理解 OpenStack Swift (2):架构、原理及功能 [Architecture, Implementation and Features]
  5. power
  6. Apache 常用伪静态配置
  7. DataGridView的单元格控制只能输入数字
  8. unity, 使导入的材质名与3dmax中一致
  9. 利用ajax获取到的网页源码不能执行js代码
  10. python re.sub
  11. 版本控制-git的使用
  12. uva 10976 Fractions Again(简单枚举)
  13. spring @Component
  14. 在Flex中用于处理XML对象的E4X 方法
  15. 阿里云VPC绑定EIP实现SNAT
  16. Python 开发之路
  17. awk 实用技巧
  18. 我的Java设计模式-单例模式
  19. There is no action xxxFun defined for api controller api/subitem
  20. mysql比较运算符和函数

热门文章

  1. 04.委托Delegation
  2. C++利用模板在Windows上快速调用DLL函数
  3. 给每个li延时添加样式动画效果(setInterval,clearInterval)
  4. Windows协议 LDAP篇 - 域权限
  5. Android 已发行多年,移动 App 已经趋近饱和,那么 Android 开发还会有那么吃香吗?
  6. 搭建NFS文件共享
  7. 关于const声明一些东西
  8. 数据结构与算法-排序(七)希尔排序(Shell Sort)
  9. CAS 5.3使用MySQL数据库验证
  10. Proteus仿真—51单片机实现AC信号测频、显示、双机通信