-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JS基础测试33 #29
Comments
//zxx: 1. 应该返回字符串;2. 应该补全末尾的0 |
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: 滴~满分~
|
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 |
以谷歌浏览器作答
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);
}; |
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;
}
});
}
}; |
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 |
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)) |
产生这种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;
}; |
经测试,只有当保留小数位后面仅为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 //zxx: 赞不一样的思路,富有创造力 |
|
// 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)
} |
第五/六问 demo
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) : '')
)
}
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)
}
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做测试
参考简书上的一篇文章做了小调整 // 第五题
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" |
第五题: 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 |
本期要点:
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);
} |
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);
} |
多谢反馈~ |
一转眼又到周三了,本期小测题目如下,围绕toFixed()方法展开:
大家提交回答的时候,注意缩进距离,起始位置从左边缘开始;另外,github自带代码高亮,所以请使用下面示意的格式。
其它:
The text was updated successfully, but these errors were encountered: