模拟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 法
目前我假设,存在某种稠密程度的数组,使得两种方法的效率等同。尼玛..数学