美文网首页
原生实现parseInt和关于1进制

原生实现parseInt和关于1进制

作者: ceido | 来源:发表于2018-09-06 16:21 被阅读0次

    前言

    开始是由一道笔试题引起的思考,问:
    ["1", "2", "3"].map(parseInt);的返回结果是?

    image.png

    原因是map的回调函数传入了三个参数,也就是说parseInt调用其实是这样的: parseInt(item, index, array);

    parseInt只接收两个参数,第三个被忽略,第二个是进制。所以parseInt('2', 1); parseInt('3', 2);都返回了NaN,而parseInt('1', 0);返回了1,是因为传入0进制是无效的,最终会按10进制处理。

    其实我理解的进制,其实就是一个有效数字范围而已,2进制的有效范围为0,1所以有:

    image.png

    可以看到'2'属于无效的。

    正文

    基于这个理解,下面贴出原生实现parseInt方法,自己实现一遍的确有点蛋疼,但它能让你真正的理解parseInt。并且在一次面试中面试官就要求手撕 parseInt,当时是磕磕绊绊写出来了,回去后对细节都进行处理,各种刁钻输入都和原生parseInt结果一样:

          function myParse(data, radix = 10) {
            if (radix > 36 || radix < 2 || !Number.isInteger(radix)) { // 进制必须是大于等于2和小于等于36的整数
                return NaN;
            }
            if (radix === 0) {
                radix = 10;
            }   
    
            let str = data.toString().toLowerCase(); // parseInt本质就是字符串转整数,即使你输入的是数字,也会先给你转为字符串
    
            for (var i = 0; i < str.length; i++) { // 找出进制内有效的字符,直到遇到无效字符为止
                let char = str[i];
                // 要区分 是 0-9 或者是 a-z   并且属于合法范围
    
                if (/[0-9]/.test(char)) {
                    if ((char | 0) >= radix) {
                        break;
                    }
                } else if (/[a-z]/.test(char)) {
                    if (char.charCodeAt() - 86 > radix) {
                        break;
                    }
                } else {
                    break;
                }
    
            }
    
            let validStr = str.substr(0, i);
            let len = validStr.length;
    
            if (len === 0) {
                return NaN;
            }
    
            let res = 0;
    
            for (let i = 0; i < len; i++) { // 对有效字符进行计算
                let n = 0;
                let char = validStr[i];
                if (/[0-9]/.test(char)) {    
                    n = char | 0;
                } else { // 如果是字母
                    n = char.charCodeAt() - 87; // 这公式刚好对应,a 对应 10,b 对应 11...,z 对应 35
                }
                res += n * (radix ** (len - i - 1));
            }
    
            return res;
        }
    
        console.log(myParse(1/0, 19));
        console.log(myParse(0.000008));
        console.log(myParse(false, 16));
        console.log(myParse(103, 2));
        console.log(myParse(new String(42), 2));    
    
    自己实现的parseInt
    image.png

    更进一步

    本来问题到这里就解决了,但我想,'2'无法使用1进制表示,所以parseInt('2', 1)NaN。所以那么0可以吗,我试了一下:parseInt('0', 1); 也是NaN

    一进制是存在的,但是竟然没有一个数字能用一进制来表示?0也不可以。

    这好像是数学问题了。

    要表示一个自然数N,我们得先选用一个符号来代表1,然后将之重复N次。举例来说,使用 | 作为符号,数字5则以|||||表示。就好像数手指一样,一根手指就为1。

    想想也是,如果用0表示的话,00000应该就是5,但是计算
    0⋅Math.pow(1, 5) + 0⋅Math.pow(1, 4) + 0⋅Math.pow(1, 3) + 0⋅Math.pow(1, 2) + 0⋅Math.pow(1, 1)的结果是0,这显然矛盾。

    所以,记住parseInt的进制有效输入是整数2~36,如果输入了0,则会按照10进制处理。而其他进制都返回了NaN。

    image.png

    参考链接:

    ["1", "2", "3"].map(parseInt)为什么结果是[1, NaN, NaN]
    What would base 1 be?

    相关文章

      网友评论

          本文标题:原生实现parseInt和关于1进制

          本文链接:https://www.haomeiwen.com/subject/nehxgftx.html