首页 > 代码库 > 温故知新: 从parseInt开始

温故知新: 从parseInt开始

  工作中,几乎习惯了大量使用方便的工具库(如underscore、lodash),但是长期的依赖,却有可能在我们注意不到的地方出现黑天鹅,笔者最近就碰到了这样一件例子:  

    parseInt(9e-10);

  本身是一句很简单的代码,只是把一个浮点数转换为整型,但是结果却出乎意料是9,所谓恶魔都藏在细节中,果不其然,parseInt的内部实现似乎并不是专门面向数字的。我们都知道parseInt有一些很有趣的特性:

  //去掉单位“px”
  let left = parseInt(YourDom.style.left); //转换16进制数
  let hex = parseInt(‘ff‘, 16)

  但是,往往都忽略了为什么它会有这样的特性,于是笔者趁着周末适逢的大雨,饶有兴致的自己简单实现了一下parseInt:

let reg = /[^-\d]/;
let pureReg = /[^\d]/;

function _slice(str, startIndex, endIndex){
    if(endIndex > startIndex){
        return str.slice(startIndex, endIndex);
    }else{
        return str;
    }
}

function $parseInt(val){
    let _val = val;

    if(typeof(_val) !== ‘string‘){
        _val = _val.toString();
    }

    let strIndex = _val.match(reg) && _val.match(reg).index;

    if(strIndex == 0){
        return NaN;
    }

    let _str = _slice(_val, 0, strIndex);

    let negativeFlag = _str.indexOf(‘-‘) === 0 ? ‘-‘ : ‘‘;

    if(negativeFlag){
        _str = _str.slice(1);
    }

    strIndex = _str.match(pureReg) && _str.match(pureReg).index;
    _str = _slice(_str, 0, strIndex);

    return +(negativeFlag + _str);
}

  当然,笔者并没有实现原api中radix的相关功能,所以代码其实是比较少的,下面简单梳理下思路:

  首先,我们需要进行参数检测:   

   //如果参数的类型不为string和number,则调用它的toString方法,主要用于处理parseInt(Array)和parseInt(Number)的情况
    if(typeof(_val) !== ‘string‘){
        _val = _val.toString();
    }

  这样,我们得到的就是一个字符串了,接着我们找到字符串中第一个不为整型数据应该具备的字符的位置,例如(‘9e-10‘中,e就不应该是整型应该具备的字符),然后通过字符串的slice方法取出满足的部分(如上例中的‘9‘)。

  接着,我们需要简单的处理下符号,毕竟整型包含正数和负数,规则其实和之前处理非法字符的思路是一致的: 

    //首先判断负号是否出现在最前面,是则将它取出来
    let negativeFlag = _str.indexOf(‘-‘) === 0 ? ‘-‘ : ‘‘;

    if(negativeFlag){
        _str = _str.slice(1);
    }
  //然后再剩余的字符串中寻找负号,按之前的策略处理
    strIndex = _str.match(pureReg) && _str.match(pureReg).index;
    _str = _slice(_str, 0, strIndex);

  然后,就可以得到一个parseInt方法了,笔者命名为$parseInt。

return +(negativeFlag + _str);

  其实,回过头来,parseInt这样非常简单的方法内部需要考虑的情况也是非常的多的,特别如果还有‘.‘和‘+‘,情况则更为复杂,parseInt的场景中只有‘-‘,反而还算是比较简单的,不过也正由于它的这种特性,对于浮点数的处理才会出现parseInt(9e-10)===9的奇怪现象,不过笔者仅是使用了几个例子反推的内部实现,究竟parseInt具体应该是怎么实现的,还需要翻看一下文档才能真正明确。

  随着前端圈的发展日趋完善,不断的框架、工具库层出不穷,常年居于顶层的我们可能都渐渐的远离了底层实现,但在某些具体的场景里,对这些底层实现的掌握,却有助于我们更好的处理好我们的日常工作,正如古人云“知其然,知其所以然”。其实,无论是工作,还是生活,保持一颗好奇心,我们的世界也会越来越大,越来越有意思。

  P.S.本文中的$parseInt仅基于以下几个例子实现,仅作抛砖引玉使用,并非parseInt的完整实现,请注意:

  

parseInt([1]); //1
parseInt(+0); //0
parseInt(-1); //-1
parseInt(123.123); //123
parseInt(‘-123-345‘);//-123

  

  

  

  

温故知新: 从parseInt开始