用javascript来实现toString、parseInt、parseFloat

264 阅读1分钟

实现toString

先实现整数的2进制toString方法

Number.prototype._toString = function() {
    let str = '', flag = this < 0 ? '-' : '';
    let num = Math.abs(this);
    do{
        str = num % 2 + str;
        num = Math.floor(num / 2);
    } while (num);
    return flag + str;
}

然后实现小数的2进制toString方法

Number.prototype._toString = function() {
    let str = '', flag = this < 0 ? '-' : '';
    let integer = Math.floor(Math.abs(this));
    let decimal = Math.abs(this) - integer;
    do{
        str = integer % 2 + str;
        integer = Math.floor(integer / 2);
    } while (integer);
    if (decimal) {
        str += '.';
        do {
            const t = decimal * 2;
            str += (t < 1 ? '0' : '1');
            decimal = t < 1 ? t : t - 1;
        } while (decimal && str.length < 54);
    }
    return flag + str;
}

接着添加参数,实现toString(radix)方法

Number.prototype._toString = function(radix = 10) {
    if (radix < 2 || radix > 36) throw new RangeError("toString() radix argument must be between 2 and 36");
    let str = '', flag = this < 0 ? '-' : '';
    let integer = Math.floor(Math.abs(this));
    let decimal = Math.abs(this) - integer;
    const numArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    do{
        str = numArr[integer % radix] + str;
        integer = Math.floor(integer / radix);
    } while (integer);
    if (decimal) {
        str += '.';
        do {
            const t = decimal * radix;
            const i = Math.floor(t);
            str += numArr[i];
            decimal = t - i;
        } while (decimal && str.length < 54);
    }
    return flag + str;
}

最后处理小数精度问题,上述方法精度远超原生精度,需要进行删减。javascript表示数字有1位符号位,11位指数部分,52位小数部分。

Number.prototype._toString = function(radix = 10) {
    if (radix < 2 || radix > 36) throw new RangeError("toString() radix argument must be between 2 and 36");
    let str = '', flag = this < 0 ? '-' : '';
    let integer = Math.floor(Math.abs(this));
    let decimal = Math.abs(this) - integer;
    const numArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
    do{
        str = numArr[integer % radix] + str;
        integer = Math.floor(integer / radix);
    } while (integer);
    if (decimal) {
        str += '.';
        const maxLen = getMaxLen(radix) + 1;
        do {
            const t = decimal * radix;
            const i = Math.floor(t);
            str += numArr[i];
            decimal = t - i;
        } while (decimal && str.length < maxLen);
    }
    function getMaxLen(radix) {
        let num = Math.pow(2, 53);
        let maxLen = 0;
        while(num > 1) {
            num = Math.floor(num / radix);
            maxLen++;
        }
        return maxLen;
    }
    return flag + str;
}

实现parseInt

先实现10进制的parseInt方法

window._parseInt = function (str) {
    str = String(str).trim();
    let index = ['-', '+'].indexOf(str.charAt(0));
    if (index > -1) {
        str = str.substring(1, str.length);
    }
    let i = 0, res = '';
    while(str.charAt(i) <= '9' && str.charAt(i) >= '0') {
        res += str.charAt(i++);
    }
    return res == '' ? NaN : +res * Math.pow(-1, index + 1);
}

最后实现parseInt(str, radix)方法

window._parseInt = function (str, radix) {
    if (radix < 2 || radix > 36) return NaN;
    str = String(str).trim();
    const index = ['-', '+'].indexOf(str.charAt(0));
    if (index > -1) {
        str = str.substring(1, str.length);
    }
    if (!radix) {
        if (str.startsWith('0x') || str.startsWith('0X')) {
            str = str.substring(2, str.length);
            radix = 16;
        } else {
            radix = 10;
        }
    }
    let i = 0, res = 0;
    const numArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'].slice(0, radix);
    while(numArr.includes(str.charAt(i).toLowerCase())) {
        res *= radix;
        res += numArr.indexOf(str.charAt(i++).toLowerCase());
    }
    return i == 0 ? NaN : res * Math.pow(-1, index + 1);
}

实现parseFloat

window._parseFloat = function(str) {
    let num = _parseInt(str, 10);
    if (isNaN(num)) return num;
    str = String(str).split('.')[1];
    if (!str) return num;
    const isMinus = num < 0 ? -1 : 1;
    let i = 0;
    const numArr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    while(numArr.includes(str.charAt(i))) {
        num += numArr.indexOf(str.charAt(i++)) / Math.pow(10, i) * isMinus;
    }
    return num;
}