• 【JS】温故知新: 从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
    

      

      

      

      

  • 相关阅读:
    公平锁和非公平锁
    读写锁StampedLock的思想
    线程工作窃取算法
    关于SQL注入的问题以及解决方法
    简单工厂模式、工厂模式和抽象工厂模式
    RestFul的无状态规则详解
    Identity Server 4 中文文档(v1.0.0) 目录
    第3章 支持和规范
    第2章 术语
    第1章 背景
  • 原文地址:https://www.cnblogs.com/mfoonirlee/p/6986041.html
Copyright © 2020-2023  润新知