最近在工作過程中碰到一個隱藏的bug,經調試發現竟然是toFixed函數不可靠的結果引起的。后端同學在處理價格比較的時候,用foFixed進行價格的四舍五入之后,竟然發現比較的結果有問題;
大家都知道,Number類型的變量有個toFixed方法,該方法將Number四舍五入為指定小數位數的數字,以字符串返回。
IE:
0.6 .toFixed(0); // 0 1.6 .toFixed(0); // 2
Chrome:
0.6 .toFixed(0); // 1 1.6 .toFixed(0); // 2
另外還發現,就算是同在Chrome里,四舍五入也不靠譜:
( 0.035 ).toFixed( 2 ); // 0.04 ( 0.045 ).toFixed( 2 ); // 0.04
這次IE倒是靠譜了:
( 0.035 ).toFixed( 2 ); // 0.04 ( 0.045 ).toFixed( 2 ); // 0.05
結論 :toFixed()函數靠不住,如果有需要精確控制的情況,還是自己寫個方法比較好。比如:
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
