前言
最近的兩個專案中都有涉及到資料統計的部分,一般來說金額的資料都是選擇儲存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"
我的處理辦法很粗糙,希望各位多多給出意見。