前言
最近的两个项目中都有涉及到数据统计的部分,一般来说金额的数据都是选择保存2位小数,以前是使用JavaScript原生对象Number的toFixed方法。但是在测试中出现了3.235.toFixed(2) = 3.23的问题。查了下资料发现是因为浮点数的存储产生的问题。最后就自己封装了一个函数来解决这个问题。
1. toFixed失去准确性的原因
关于浮点数的存储我了解不多,这里推荐这个文章给需要的同学JavaScript 浮点数陷阱及解法。
2. 封装toFixed
2-1 实现思路
大体的思路是先分2部分,一是整数部分。整数部分不需要对值进行修改,为了和Number.toFixed保持一致,需要补上对应的0 (8.toFixed(2) => 8.00);
小数部分要做3个判断,当前小数后位数与要保存的位数进行比较。等于的直接返回,当前小数后位数小于要保存的位数就舍弃掉多余的部分。最后一种情况要针对正负数进行不同的处理,详情见下方代码。
注意:返回的结果都是字符串。
2-2 代码
let tofixed = (value, holdLen) => {
value = value.toString();
let dotIndex = value.indexOf(".");
//判断是否为整数
if (dotIndex === -1) {
//少几位就补几位0
let integerStr = ".";
for (let i = 0; i < holdLen; i++) {
integerStr = integerStr + '0';
}
return value + integerStr;
}
//获取小数点前后的字符串
let dotBefore = value.split(".")[0];
let dotAfter = value.split(".")[1];
//小数点后与要保留的位数进行判断出来
let result = "";
if (dotAfter.length === holdLen) {
result = value;
} else if (dotAfter.length < holdLen) {
let forlength = holdLen - dotAfter.length
//少几位就补几位0
for (let i = 0; i < forlength; i++) {
dotAfter = dotAfter + '0';
}
result = dotBefore + "." + dotAfter;
} else {
//获取到要四舍五入的位置后一个数字的值
let digit = value.substr(dotIndex + holdLen + 1, 1);
if (digit >= 5) {
let temp = Math.pow(10, 0 - holdLen);
//负数和正数的四舍五入判断
parseFloat(value) > 0 ? value = parseFloat(value) + temp : value = parseFloat(value) - temp;
value = value.toString();
}
result = value.substr(0, dotIndex + holdLen + 1);
}
return result;
}
console.log(tofixed(1.335, 2));
console.log(tofixed(2.1, 3));
console.log(tofixed(-8.546, 2));
console.log(tofixed(-9, 3));
//打印结果
"1.34"
"2.100"
"-8.55"
"-9.000"
我的处理办法很粗糙,希望各位多多给出意见。