parseInt的实现和关于1进制

字数 634阅读 48

之前这文章没有贴出代码,可能就没有人看。这本是挺有趣的思考。现在贴出代码不知有人看不?嘻嘻。

首先是由一道笔试题开始,问:
["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结果一样:

<script type="text/javascript">
      function myParse(data, radix = 10) {
        if (radix > 36 || radix < 2 || !Number.isInteger(radix) || radix !== 0) { // 进制必须是大于等于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));    

</script>

本来问题到这里就解决了,但我想,'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?

推荐阅读更多精彩内容