• 模拟ES5 Array.prototype.reduce


    一. 前言

    收到教主博客的启发,决定在不支持reduce的浏览器里模拟一下该函数。这里先做一下铺垫:

    1. 数组里的 undefined 和坑

    var a = [undefined,,2];
    a[3] = undefined;
    a[100] = 99;//出现一个稀疏数组
    
    a[0] === undefined;//true
    a[1] === undefined;//true
    a[3] === undefined;//true
    a[50] === undefined;//true
    
    0 in a;//true
    1 in a;//false
    3 in a;//true
    50 in a; //false

    我把 a[1] 和 a[50] 这种没有显式赋值的元素叫做"坑",坑爹的坑~

     

    2. 

     

    二. 代码

    1. 版本一

    使用 for(var i =0,l=arr.length; i<l; i++) 来遍历数组元素,虽然能有效模拟对稀疏数组的reduce操作,但效率过低. 

    //化简函数 reduce
    if(! Array.prototype.reduce)
    {
        Array.prototype.reduce = function(f , initValue){
            
            var i = bg = ret = null , ed = this.length ? this.length : 0;//
    
            if(this.length === 0 && arguments.length < 2){
                //如果数组为空并且未提供初始值,抛出 类型异常
                throw new TypeError('TypeError: Inside Array.prototype.reduce , lack of valid parameter');
            }else if(arguments.length >= 2){
                //否则,如果传入了initValue,则从 initValue 和 this[0] 开始运算
                bg = 0;
                ret = initValue;
            }else{
                //否则,表明未提供 initValue, 则从 this[0] 和 this[1] 开始运算
                bg = 1;
                ret = this[0];
            }
    
            for(i=bg; i<ed; i++)
            {
                //如果 this[i] 不是稀疏数组里的那种坑
                if(i in this){
                    ret = f(ret , this[i] , i , this);
                }
            }
            return ret;
        };
    }

     这个版本的问题在于,应付稀疏数组效率极低,例如,var a=[0]; a[100000] = 10000; 为了求得这个数组里的元素的和,使用方法一,将执行一个 10000 次的循环,其中 9999 次是浪费的。

     

     

    2. 版本二

    使用 for in 结构来遍历数组,能高效应对稀疏数组

    //化简函数 reduce
    if(! Array.prototype.reduce)
    {
        Array.prototype.reduce = function(f , initValue){
    
            if(this.length === 0 && arguments.length < 2){
                //如果数组为空并且未提供初始值,抛出 类型异常
                throw new TypeError('TypeError: Inside Array.prototype.reduce , lack of valid parameter');
            }
            var i = 0,//
                p = null,//property , 属性
                r = /(^0$)|(^[1-9]\d*$)/,//匹配 '0','103' , '23' ,  ,不匹配'00','01'
                bg = -1,
                idx = -1,
                idxs = [];
    
            //获取所有有效的下标,根据下标升序排序
            for(p in this){
                if(r.test(p)){
                    idxs[i++] = parseInt(p);
                }
            }
    
            idxs.sort(function(idx1,idx2){
                return idx1 - idx2;
            });
    
    
            //开始求值
            if(arguments.length >= 2){
                bg = 0;
                ret = initValue;
            }else{
                bg = 1;
                ret = this[0];
            }
            for(i=bg,l=idxs.length; i<l; i++)
            {
                idx = idxs[i];
                ret = f(ret , this[idx] , idx , this);
            }
    
            return ret;
        };
    }

     

    不过,这个版本还是有效率问题的,相对于“稀疏数组”肯定有“稠密数组”,对于稠密的数组,显然是方法一好,方法二的消耗在于,需要一个数组的空间来装索引,即代码中的 idxs。

    3. 版本三

    以上两个版本各有千秋,针对稠密数组和稀疏数组各有好坏。接下来给个综合版,我的思路很简单,先罗列一下:

    1) 判断是否稀疏

    2) 稀疏则用for in 法,稠密则用 for i<len 法

    目前我假设,存在某种稠密程度的数组,使得两种方法的效率等同。尼玛..数学

  • 相关阅读:
    Oracle查看正在执行的存储过程的sid---转
    使用WITH子句重用子查询
    oracle解决显示数据的层次问题--实现数据缩进
    oracle9i、10g、11g区别 --转
    oracle10g安装在裸设备上
    在Linux系统上面创建使用裸设备的数据库
    监控Oracle数据库的常用shell脚本-转
    sql server使用维护计划定时备份完整数据库、差异数据库
    使用Advanced Installer14.3 简单打包windows窗体应用程序
    SVG Path标签 A 参数
  • 原文地址:https://www.cnblogs.com/yaozhiyi/p/2750272.html
Copyright © 2020-2023  润新知