zhangxinxu/quiz

JS基础测试33

Opened this issue · 21 comments

一转眼又到周三了,本期小测题目如下,围绕toFixed()方法展开:

大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。

```js
// 你的JS代码写在这里
 ```

其它:

  1. 首位答题者可获得额外2积分和直播翻牌机会;
  2. 本次答疑直播为6月15日上午10:00,会和上期CSS小测一起答疑,大约40多分钟;
  1. "1"
  2. "2"
  3. "0.04"
  4. "0.04"
  5. Number.prototype.toFixed=function(v){return (this>0?1:-1)*parseInt(Math.round(Math.abs(this) * Math.pow(10,v))) / Math.pow(10,v)}
  6. String.prototype.toFixed=function(v){return (this>0?1:-1)*parseInt(Math.round(Math.abs(this) * Math.pow(10,v))) / Math.pow(10,v)}
//zxx: 1. 应该返回字符串;2. 应该补全末尾的0
Chrome Firefox IE11
0.6.toFixed(0) 1 1 1
1.6.toFixed(0) 2 2 2
0.035.toFixed(2) 0.04 0.04 0.04
0.045.toFixed(2) 0.04 0.04 0.05
Number.prototype.toFixed = myToFixed;
String.prototype.toFixed = myToFixed;

function myToFixed(digits = 0) {
  let num = String(this);

  // 小数位不足时后置补零
  const postfixZero = s => {
    let len = digits;

    if (s.indexOf('.') > 0) {
      len = digits - s.split('.')[1].length;
    } else if (len > 0) {
      s += '.';  // 整数位后补小数点
    }

    return s + '0'.repeat(len);
  };

  digits = parseInt(digits, 10);

  if (isNaN(digits)) {  // 非数值
    throw new Error('digits argument must be a number(or string number)');
  }

  if (digits < 0) {  // 负数
    throw new Error('digits argument must be greater than or equal to 0');
  }

  if (!isFinite(num)) {  // +-Infinity
    return num;
  }

  if (num.indexOf('.') > 0) {
    let times = Math.pow(10, digits);  // 根据小数位长度获取升幂倍数
    num = Math.round(num * times) / times + '';  // 四舍五入,降幂
  }

  return postfixZero(num);
}

测试用例:

console.group('普通场景测试');
  console.log(0.6.toFixed(0));  // "1"
  console.log(1.6.toFixed(0));  // "2"
  console.log(0.035.toFixed(2));  // "0.04"
  console.log(0.045.toFixed(2));  // "0.05"
console.groupEnd();    
  
console.group('进阶场景测试');
  console.log(Math.PI.toFixed(10));  // "3.1415926536"
  console.log(0.9.toFixed());  // "1"
  console.log(Number(5).toFixed(2));  // "5.00"
  console.log(3..toFixed(3));  // "3.000"
  console.log(.5.toFixed('3'));  // "0.500"
  console.log(1.2345.toFixed(2.6));  // "1.23"
console.groupEnd();
  
console.group('参数异常测试');
  console.log(Infinity.toFixed(5));  // "Infinity"
  console.log(0.5.toFixed(-2));  // Error: digits argument must be greater than or equal to 0
  console.log(0.5.toFixed(null));  // Error: digits argument must be a number(or string number)
console.groupEnd();
//zxz:  滴~满分~

2019-07-21:无法通过 1.005.toFixed(2) 的测试用例,期望返回 1.01 实际返回 1.00

  1. 1
  2. 2
  3. 0.04
  4. 0.05
Number.prototype.toFixed = String.prototype.toFixed = function (number) {
    if(isNaN(number)) return;
    return parseInt(this * Math.pow(10, number) + 0.5) / Math.pow(10, number);
}
//zxx: 1. 应该返回字符串;2. 应该补全末尾的0

参考了这个被科普了ie和谷歌的区别

以谷歌浏览器作答

  1. 1
  2. 2
  3. 0.04
  4. 0.04
    String.prototype.toFixed = Number.prototype.toFixed = function (fractionDigits) {
        var num = this;
        if(isNaN(num)){
            throw Error(`${num}不是一个数字`);
        }
        return Math.round(num * Math.pow(10, fractionDigits)) / Math.pow(10, fractionDigits);
    };
  1. '1'
  2. '2'
  3. '0.04'
  4. '0.04' (Chrome); '0.05' (IE)
Number.prototype.toFixed = function(d) {
	d = isNaN(d) ? 0 : parseInt(d);
	if (d < 0 || d > 20) {
        throw new RangeError('toFixed() digits argument must be between 0 and 20');
    }
    var val = this.toString();
    if (val.indexOf('.') < 0) {
    	return val;
    }
    if (d === 0) {
    	return val.replace(RegExp('^([0-9]+)(?:\\.)([0-9])[0-9]*$'), function(m,intPart, judgePart) {
    		return (+judgePart >= 5 ? ((+intPart + 1) + '') : intPart);
    	});
    } else {
	    return val.replace(RegExp('^([0-9]+\\.)([0-9]*)$'), function(m, intPart, fractionalPart) {
	    	return intPart + (fractionalPart.length < d ? (fractionalPart + Array(d - fractionalPart.length + 1).join('0')) : fractionalPart);
	    }).replace(RegExp('^([0-9]+)(\\.)([0-9]{' + d + '})([0-9])[0-9]*$'), function(m, intPart, dotPart, keepPart, judgePart) {
	    	var orgLen = keepPart.length;
	    	var newVal = (+judgePart >= 5 ? (+keepPart + 1) : +keepPart).toString();
	    	if (newVal.length > orgLen) {
	    		return (+intPart + (+newVal.slice(0,1))) + dotPart + newVal.slice(1);
	    	} else if (newVal.length < orgLen) {
	    		return intPart + dotPart + Array(orgLen - newVal.length + 1).join('0') + newVal;
	    	} else {
	    		return intPart + dotPart + newVal;
	    	}
	    });
    }
};
String.prototype.toFixed = function(d) {
	if (isNaN(this)) {
		return NaN;
	}
	d = isNaN(d) ? 0 : parseInt(d);
	if (d < 0 || d > 20) {
        throw new RangeError('toFixed() digits argument must be between 0 and 20');
    }
    var val = (+this).toString();
    if (val.indexOf('.') < 0) {
    	return val;
    }
    if (d === 0) {
    	return val.replace(RegExp('^([0-9]+)(?:\\.)([0-9])[0-9]*$'), function(m,intPart, judgePart) {
    		return (+judgePart >= 5 ? ((+intPart + 1) + '') : intPart);
    	});
    } else {
	    return val.replace(RegExp('^([0-9]+\\.)([0-9]*)$'), function(m, intPart, fractionalPart) {
	    	return intPart + (fractionalPart.length < d ? (fractionalPart + Array(d - fractionalPart.length + 1).join('0')) : fractionalPart);
	    }).replace(RegExp('^([0-9]+)(\\.)([0-9]{' + d + '})([0-9])[0-9]*$'), function(m, intPart, dotPart, keepPart, judgePart) {
	    	var orgLen = keepPart.length;
	    	var newVal = (+judgePart >= 5 ? (+keepPart + 1) : +keepPart).toString();
	    	if (newVal.length > orgLen) {
	    		return (+intPart + (+newVal.slice(0,1))) + dotPart + newVal.slice(1);
	    	} else if (newVal.length < orgLen) {
	    		return intPart + dotPart + Array(orgLen - newVal.length + 1).join('0') + newVal;
	    	} else {
	    		return intPart + dotPart + newVal;
	    	}
	    });
    }
};
—— chrome firefox ie
0.6 1 1 1
1.6 2 2 2
0.035 0.04 0.04 0.04
0.045 0.04 0.04 0.05

jsbin

Number.prototype.toFixed = __toFixed;
String.prototype.toFixed = __toFixed;
console.log(0.6.toFixed(0));
console.log(1.6.toFixed(0));
console.log(0.035.toFixed(2));
console.log(0.045.toFixed(2));
console.log(new Number(200).toFixed(2));
console.log(new Number(200).toFixed(0));
console.log(new Number(1.23456789123456789).toFixed(5));

console.log("0.6".toFixed(0));
console.log("1.6".toFixed(0));
console.log("0.035".toFixed(2));
console.log("0.045".toFixed(2));
console.log("200".toFixed(2));
console.log("200".toFixed(0));
console.log("1.23456789123456789".toFixed(5));

function __toFixed(val) {
  const value = +this.toString();
  const decimal_number = this.toString().replace(/\d*\./, "").length;
  const denominator = 10 ** (decimal_number - val > 0 ? decimal_number -
    val : 0);
  let current_value = Math.round(value * 10 ** decimal_number / denominator) * denominator / 10 ** decimal_number + "";
  if (/\./.test(current_value)) {
    const current_decimal_number = current_value.replace(/\d*\./, "").length;
    if (current_decimal_number < val) {
      current_value += "0".repeat(val - current_decimal_number);
    }
  } else if (val) {
    current_value += "." + "0".repeat(val);
  }
  return current_value;
}
//zxx: 测试通过
第一题:'1'
第二题: '2'
第二题: '0.04'
第四题: '0.04' /chrome;'0.05'/ie
第五题:
Number.prototype.toFixed = function(n){
    n = parseInt(n)
    if (n < 0) return NaN 

    let num = this.valueOf()
    let numStr = num +''
    let pointPos = numStr.indexOf('.')
    if (pointPos > -1){
        //有小数部分
        let decimal = numStr.slice(pointPos+1)
        if (decimal.length < n) {            
            //小数位需要填零
            let ret = numStr + (new Array(n - decimal.length).fill(0).join(''))

            return ret

        }else {
            //正常四舍五入
            //Math.round 对于负数也会有-4.5 =》 4 ; 4.5 =》 5
            let m = Math.pow(10, n)
            let flag = num > 0
            let t = parseInt(Math.round(Math.abs(num) * m)) / m
            t = flag ? t : -t
            return t+''
        }
    }else {
        //整数
        return num+ ( n > 0 ? '.' + (new Array(n).fill(0).join('')) : '')
    }

}

第六题:
String.prototype.toFixed = function(n){
    let num = +this
    if (isNaN(num)) return NaN
    return num.toFixed(n)
}


//测试
console.log('0.6'.toFixed(0)) //1
console.log('1.6'.toFixed(0))  //2
console.log('0.035'.toFixed(2)) //0.04
console.log('0.045'.toFixed(2)) //0.05
console.log('-0.045'.toFixed(2)) //-0.05
console.log(('-100.525').toFixed(5)) //-100.125
console.log('100.8123'.toFixed(0)) //101

code pen demo

chrome 
1. '1'
2. '2'
3.  '0.04'
4.  '0.04'
5.
// 数字+1
function numAdd(str) {
    let flag = 1, newNum = ''
    for (let i = str.length - 1; i >= 0; i--) {
        if (str[i] === '.') {
            newNum = '.' + newNum
            continue
        }
        let res = (str[i] >> 0) + flag
        flag = res >= 10 ? 1 : 0;
        if (i === 0) {
            newNum = (str[i] === '-' ? '-' : '') + res + newNum
        } else {
            newNum = (flag ? '0' : res) + newNum
        }
    }
    return newNum
}
Number.prototype.toFixed = function (num) {
    let strNum = (this + '')
    const pointPos = strNum.indexOf('.')
    const strArr = strNum.split('.')

    // 如果保留有效数字的值比小数点后的数字大,补0
    if (num !== 0) {
        if (pointPos === -1) {
            strNum += '.'
        }
        strNum = strNum.padEnd((strNum.length - pointPos - 1) + num, '0')
    }
    // 小数再判断四舍五入
    if (pointPos !== -1) {
        if (strArr[1].length > num) {
            const newStr = strArr[0] + '.' + strArr[1].slice(0, num)
            return (strArr[1][num] >= 5 ? numAdd(newStr) : newStr).replace(/\.$/, '')
        } else {
            return strNum
        }
    }
    return strNum
}
console.log((0.6).toFixed(0),
    (1.6).toFixed(0),
   ( 0.035).toFixed(2),
    (0.045).toFixed(2))

6.
String.prototype.toFixed = function (num) {
            if (parseFloat(num) + '' === 'NaN') {
                return num
            } else {
                return Number.prototype.toFixed.call(this, num)
            }
       }

console.log('0.6'.toFixed(0),
    '1.6'.toFixed(0),
    '0.035'.toFixed(2),
    '0.045'.toFixed(2))
tzmy commented

demo

1. 1
2. 2
3. 0.04
4. 0.04

产生这种bug的原因网上说是丢失精度,不过我觉得有可能是此方法是采用了其它的舍入方法,类似于四舍六入五留双的方法,当然也没有完全符合这些规则。 参考

Number.prototype.toFixed = function (num) {
    return myFixed(this.valueOf(),num);
};
String.prototype.toFixed = function (num) {
    if(isNaN(this.valueOf())){
        return 'isNaN';
    }
    return myFixed(this.valueOf(),num);
};
function myFixed(number,num){
    var numberString = number.toString();
    var dotLength = 0;
    var fact = number;
    if(num<=0){
        return number;
    }
    var dot = numberString.split(".")[1]?numberString.split(".")[1]:'';
    var a = dot.slice(num,num+1);
    if(a!=''){
        if(parseInt(a)<5){

        }else{
            fact = Number(number) + Math.pow(10,-num);
        }
    }
    var factString = fact.toString();

    if(factString.split(".")[1]){
        fact = factString.split(".")[0]+'.' + factString.split(".")[1].slice(0,num);
    }else {
        fact = factString.split(".")[0]+'.';
    }
    fact = fact.toString();
    if(fact.split(".")[1]) {
        dotLength = dot.length;
    }
    for (var i=0;i<num-dotLength;i++){
        fact += '0';
    }
    return fact;
};
Chrome Firefox IE
0.6.toFixed(0) 1 1 1
1.6.toFixed(0) 2 2 2
0.035.toFixed(2) 0.04 0.04 0.04
0.045.toFixed(2) 0.04 0.04 0.05

经测试,只有当保留小数位后面仅为5的时候会出现预期之外的结果,改为6就正常了,或者补一位小数

var NativetoFixed = Number.prototype.toFixed;//备份

//方式一:替换小数点保留精度后面一位5为6
var MytoFixed = function(digits){
    var reg = new RegExp('(\\d*.\\d{' + digits + '})5(\\d*)', 'g')
    var number = Number(this.toString().replace(reg, '$1' + 6 + '$2'));
    return NativetoFixed.call(number,digits);
}

//方式二:给小数点保留精度后面补一位小数
var MytoFixed = function(digits){
    var number = Number(this)+Math.pow(10,-digits-1);
    return NativetoFixed.call(number,digits);
}

Number.prototype.toFixed = MytoFixed;
String.prototype.toFixed = MytoFixed;

//有错误:1.0141  .toFixed = 1.0141 + 0.001 = 1.151 -> toFixed(2) = 1.15

demo

image

//zxx: 赞不一样的思路,富有创造力
  1. 1

  2. 2

  3. 0.04

  4. 0.04

  5. Number.prototype.toFixed = function(v){
    if(this === -Infinity) throw Error('-Infinity');
    if(this === Infinity) throw Error('Infinity');
    if(isNaN(this)) throw Error(this+'.toFixed is not a function')
    return parseInt(Math.round(this * Math.pow(10,v)))/Math.pow(10,v)
    }

  6. String.prototype.toFixed = function(v){
    var num = Number(this);
    if(!num) return 'Error Non-numeric string';
    return parseInt(Math.round(num * Math.pow(10,v)))/Math.pow(10,v)
    }

我极其神奇的脑洞

// 1
document.write(0.6.toFixed(0));
document.write(" ");

// 2
document.write(1.6.toFixed(0));
document.write(" ");

// 3
document.write(0.035.toFixed(2));
document.write(" ");

// 4
document.write(0.045.toFixed(2));
document.write(" ");

// 5
Number.prototype.toFixed=function(v){
  //增加 nan判断   
  if(!window.isNaN(this)){
    let numberString = this.toString().split(".");
    let isAddOne = ( numberString[1].slice(v,v+1) - 0 ) >= 5;
    let result = "";
    let beforePonit =  numberString[0]+".";

    if(v===0){
       result =  ((beforePonit + numberString[1].slice(0,v)) - 0 ) +  (isAddOne ? 1 : 0) ;
    }
    else{
      let addNumber="";
      for(let i=0;i < v-1;i++){
        addNumber = addNumber +"0";
      }
      result =  ((beforePonit + numberString[1].slice(0,v)) - 0 ) +((beforePonit+  addNumber +  (isAddOne ? 1:0) ) - 0 ) ;
    }
    return result;
  }
}

// 6
String.prototype.toFixed = Number.prototype.toFixed;
/*
*
 0.6.toFixed(0)
 "1"
 1.6.toFixed(0)
 "2"
 0.035.toFixed(0)
 "0"
 0.035.toFixed(2)
 "0.04"
 0.045.toFixed(2)
 "0.04"
*
* */
Number.prototype.oldToFixed = Number.prototype.toFixed;

Number.prototype.toFixed=function(a){
  let num = this - 0;
  a = a-0;
  if(!(a > 0 || a < 1)){
    a = 0
  }
  let times = Math.pow(10,a);
  let bigNum = num*times;
  let str = bigNum+'';
  if(str.indexOf('.')<0){
    return num.oldToFixed(a)
  }
  else{
    let numArr = str.split(".");
    let integer = numArr[0];
    let decimal = numArr[1];
    if(decimal>4){
      integer++
    }
    return integer/times
  }
}

String.prototype.toFixed=function(a){
  let num = this - 0;
  if(!(num > 0 || num < 1)){
    return num
  }
  return num.toFixed(a)
}
Chrome Firefox Safari IE
0.6.toFixed(0) 1 1 1 1
1.6.toFixed(0) 2 2 2 2
0.035.toFixed(2) 0.04 0.04 0.04 0.04
0.045.toFixed(2) 0.04 0.04 0.04 0.05

第五/六问 demo

  • 一开始实现的方法,后面经过测试发现 toFixedFirstTime(1.015,2) 测试结果出错
function toFixedFirstTime(num, pre = 0) {
  num = parseFloat(num)
  // 非负数和取整
  pre = pre < 0 ? 0 : ~~pre
  // 计算四舍五入结果
  const result = Math.round(num * Math.pow(10, pre)) / Math.pow(10, pre) + ''
  // 将结果通过小数点分割成两个数字
  const strArr = result.split('.')
  // 如果存在小数点
  if (strArr[1] !== undefined) {
    const len = strArr[1].length
    // 如果小数部分长度不及提供的数值大
    if (len <= pre) {
      return `${result}`.padEnd(pre + strArr[0].length + 1, 0)
    } else {
      return `${result}`
    }
  }
  return (
    // 加一是因为小数点的长度
    `${result}` + (pre > 0 ? '.'.padEnd(pre + 1, 0) : '')
  )
}
  • 第二次重写 toFixed 函数, 测试 toFixedSecondTime(1.015,2) 成功
function toFixedSecondTime(num, pre = 0) {
  pre = pre < 0 ? 0 : ~~pre
  const strArr = `${num}`.split('.')
  const index = `${num}`.indexOf('.')

  if (strArr[1] !== undefined) {
    const len = strArr[1].length
    // 当指定数值比原数据的小数位长
    if (len <= pre) {
      return `${num}`.padEnd(pre + strArr[0].length + 1, 0)
    } else {
      // 最后一位数
      const last = strArr[1].slice(pre, pre + 1)
      // 小数点前数字长度
      const firstLength = strArr[0].length
      // 将源数据取出小数点变为一个整数
      let str = strArr.join('').split('')
      if (last >= 5) {
        let addFlag = false
        const res = str
          // 取出小数点前以及小数点后 pre 位的数值
          .slice(0, firstLength + pre)
          // 将数组反转
          .reverse()
          // 判断是否需要进位
          .reduce((res, acc, index) => {
            if (index === 0 || addFlag) {
              acc = parseInt(acc) + 1
              addFlag = false
            }
            if (acc === 10) {
              addFlag = true
              acc = 0
            }
            res.push(acc)
            return res
          }, [])
          // 将数组反转为原来的顺序
          .reverse()
          .join('')

        // 判断 pre 是否为 0, 为 0 则不添加小数点
        return (
          `${res.slice(0, index)}` +
          (pre > 0 ? `.${res.slice(index, index + pre)}` : '')
        )
      } else {
        // 判断 pre 是否为 0, 为 0 则不添加小数点
        return `${strArr[0]}` + (pre > 0 ? `.${strArr[1].substr(0, pre)}` : '')
      }
    }
  }
  return `${num}.`.padEnd(pre + `${num}`.length + 1, 0)
}
  • 第一个测试函数失败原因为 1.015 * Math.pow(10, 2) 返回结果是 101.49999999999999, Math.round 后返回 101。返回的结果比正常的结果小了 1e-14, 经过测试将这个数值先跟原始数值相加再进行 toFixed ,可以得到期待的值
function toFixedThirdTime(num, pre) {
   pre = pre < 0 ? 0 : ~~pre
   num = parseFloat(num)
   return (num + 1e-14).toFixed(pre)
}

Number.prototype.toMyFixed = String.prototype.toMyFixed = function(pre) {
   pre = pre < 0 ? 0 : ~~pre
   num = parseFloat(this)
   return (num + 1e-14).toFixed(pre)
}
//zxx: 研究精神不错,恕我代码看得眼花,可读性这块并不算友好

弄了个turbo做测试

ie8 ie9 ie10 edge chrome firefox opera
0.6.toFixed(0) 0 1 1 1 1 1 1
1.6.toFixed(0) 2 2 2 2 2 2 2
0.035.toFixed(2) 0.04 0.04 0.04 0.04 0.04 0.04 0.04
0.045.toFixed(2) 0.05 0.05 0.05 0.05 0.04 0.04 0.04

参考简书上的一篇文章做了小调整

// 第五题
Number.prototype.toFixed = function(n) {
  const number = this;
  if (isNaN(number)) {
    return number.toString();
  }
  if (typeof(n) == 'undefined' || n == 0) {
    return (Math.round(number)).toString();
  }
  let result = number.toString();
  const arr = result.split('.');
  // 整数的情况
  if (arr.length < 2) {
    result += '.';
    for (let i = 0; i < n; i += 1) {
      result += '0';
    }
    return result;
  }
  const integer = arr[0];
  const decimal = arr[1];
  if (decimal.length == n) {
    return result;
  }
  if (decimal.length < n) {
    for (let i = 0; i < n - decimal.length; i += 1) {
      result += '0';
    }
    return result;
  }
  result = integer + '.' + decimal.substr(0, n);
  const last = decimal.substr(n, 1);
  // 四舍五入,转换为整数再处理,避免浮点数精度的损失
  if (parseInt(last, 10) >= 5&&result>0) {
    const x = Math.pow(10, n);
    result = (Math.round((parseFloat(result) * x)) + 1) / x;
    result = result.toFixed(n);
  }else if(parseInt(last, 10) >= 5&&result<0){
    const x = Math.pow(10, n);
    result = (Math.round((parseFloat(result) * x)) - 1) / x;
    result = result.toFixed(n);
  }
  return result;
};
// 第六题
String.prototype.toFixed=Number.prototype.toFixed
1. "1"
2. "2"
3. "0.04"
4. "0.04"

5-6. 下面的方法完全以字符串的方式进行处理

function toFixedFn (digits) {
  if (digits < 0) throw new Error("位数不得小于0");

  let [intNum, floatNum] = this.toString().split(".");
  // 若无小数部位,直接用原生toFixed
  if (floatNum === undefined) return parseInt(intNum).toFixed(digits);
  // 若 digits 为0,直接利用round取整
  if (digits === 0) return Math.round(this)
  // 若小数部位长度少于digits,进行补位
  if (floatNum.length < digits) {
    let diff = digits - floatNum.length
    floatNum = parseInt(floatNum) * Math.pow(10, diff)
  }
  // 小数部位模拟取整
  let reg = new RegExp(`(.{${digits}})`);
  floatNum = Math.round(floatNum.toString().replace(reg, "$1.").slice(0, digits + 2))
  floatNum = (floatNum / Math.pow(10, digits)).toString().slice(1)
  // 处理完后,进行补位
  if (floatNum.length - 1 < digits) {
    floatNum = floatNum + '0'.repeat(digits - floatNum.length + 1)
  }
  return intNum + floatNum
};

Number.prototype.toFixedNum = toFixedFn
String.prototype.toFixedNum = toFixedFn

// 测试
console.log((0.6).toFixedNum(0));   
console.log((1.6).toFixedNum(0));   
console.log((0.035).toFixedNum(2));
console.log((0.045).toFixedNum(2));
console.log((0.2).toFixedNum(6));  

console.log('0.6'.toFixedNum(0));   
console.log('1.6'.toFixedNum(0));   
console.log('0.035'.toFixedNum(2));
console.log('0.045'.toFixedNum(2));
console.log('0.2'.toFixedNum(6));  
// 输出
1
2
"0.04"
"0.05"
"0.200000"
  • 使用Node
    result:
    console.log(0.6.toFixed(0)) => 1
    console.log(1.6.toFixed(0)) => 2
    console.log(0.035.toFixed(2)) => 0.04
    console.log(0.045.toFixed(2)) => 0.04
  • chrome浏览器
    result:
    console.log(0.6.toFixed(0)) => 1
    console.log(1.6.toFixed(0)) => 2
    console.log(0.035.toFixed(2)) => 0.04
    console.log(0.045.toFixed(2)) => 0.04

第五题:

Number.prototype.toFixed = function(n) {
    var power = Math.pow(10, n);
    var value = this * power + 0.5;
    value = parseInt(value, 10) / power;
    return value;
};

第六题:

String.prototype.toFixed = function(n) {
    var num = Number(this);
    if(!num) return NaN;
    var power = Math.pow(10, n);
    var value = num * power + 0.5;
    value = parseInt(value, 10) / power;
    return value;
};
chrome 
1. 1
2. 2
3. 0.04
4. 0.04
5.
let oldtoFixed = Number.prototype.toFixed
Number.prototype.toFixed = function(n) {
    return oldtoFixed.call(Number.parseFloat(this+''+1), n)
}

// 有错误 new Number(10).toFixed(2) "101.00"
6. String.prototype.toFixed = Number.prototype.toFixed

本期要点:

  1. toFixed有两个问题,一是兼容性,二是四舍五入不符合正常的四舍五入认知。金钱计算的时候容易出问题,必须两位小数。
  2. 应该返回字符串;补全末尾的0。
  3. 机智是实现:方式一:替换小数点保留精度后面一位5为6,方式二:给小数点保留精度后面补一位小数。其中方式2是最简单的,XboxYan 和 frankyeyq 实现都有bug,下面是调整后的实现。
var oldtoFixed = Number.prototype.toFixed
Number.prototype.toFixed = function(digits){
    var length = (parseFloat(this) + '').replace(/^\d+\.?/, '').length;
    var len = length > digits ? length : digits;
    var number = Number(this) + Math.pow(10, -len-1);
    return oldtoFixed.call(number, digits);
}
var oldtoFixed = Number.prototype.toFixed
Number.prototype.toFixed = function(digits){
    var length = (parseFloat(this) + '').replace(/^\d+\.?/, '').length;
    var number = Number(this) + Math.pow(10, -length-1);
    return oldtoFixed.call(number, digits);
}

length 判断存在问题, 如果是 10.toFixed(2) 会在小数点后一位添加 1 导致返回 10.10, 所以应该判断 length 和 digits 的大小

var oldtoFixed = Number.prototype.toFixed
Number.prototype.toMyFixed = function(digits){
    var length = (parseFloat(this) + '').replace(/^\d+\.?/, '').length;
    var len = length > digits ? length : digits
    var number = Number(this) + Math.pow(10, -len-1);
    return oldtoFixed.call(number, digits);
}
var oldtoFixed = Number.prototype.toFixed
Number.prototype.toFixed = function(digits){
    var length = (parseFloat(this) + '').replace(/^\d+\.?/, '').length;
    var number = Number(this) + Math.pow(10, -length-1);
    return oldtoFixed.call(number, digits);
}

length 判断存在问题, 如果是 10.toFixed(2) 会在小数点后一位添加 1 导致返回 10.10, 所以应该判断 length 和 digits 的大小

var oldtoFixed = Number.prototype.toFixed
Number.prototype.toMyFixed = function(digits){
    var length = (parseFloat(this) + '').replace(/^\d+\.?/, '').length;
    var len = length > digits ? length : digits
    var number = Number(this) + Math.pow(10, -len-1);
    return oldtoFixed.call(number, digits);
}

多谢反馈~