模拟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 法

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

posted @ 2012-11-02 00:01  一三一四君  阅读(354)  评论(0编辑  收藏  举报