手动实现reduce方法和splice方法

今天花了一点时间手写了比较常用的一些方法的源码,其中,reduce和splice这两个方法比别的略微复杂点,就分享一下啦~

ps:flat这个方法的源码也蛮有意思的,和我的上一篇博客里面“关于实现数组扁平化”的代码很相似,就不再码一遍了。

splice方法

splice(stratIndex,delCount,ele1,ele2...)该方法表示从startIndex下标开始,删除delCount个数组元素,然后在startIndex处添加一个或多个元素(该方法会对数组产生影响)

例如

let arr = [10, 20, 30, 40, 50];
let arr1 = arr.splice(2,1);//如果delCount不写,默认删除后面所有
console.log(arr1);// 返回包含被删除元素的数组 [30]
console.log(arr);//对原数组产生影响 [10, 20, 40, 50]
let arr = [10, 20, 30, 40, 50];
let arr1 = arr.splice(2,1,11,22);
console.log(arr1);//  [30]
console.log(arr);//返回了插入新元素的数组 [10, 20, 11, 22, 40, 50]

开始实现

我的逻辑分四步:

  1. 处理startIndex,delCount边缘化的情况(例如初始下标小于0或者大于数组长度,删除数量小于0或删除数量比能删的数量多的情况)
  2. 获取删除元素,并添加到新数组中(这个比较简单,遍历完事~)
  3. 移动原数组(主要考虑三种情况:删除数量 大于/小于/等于 添加数量 ;这个关系到原数组是向前还是向后移动了)
  4. 添加新元素到原数组中(由于上一步“移动原数组”,已经给新元素腾好位了,所以这一步也只是简单的遍历啦

大纲

下面来捋捋顺哈!先给个大纲

Array.prototype.mySplice = function (startIndex, delCount, ...addElements) {
    let array = Object(this);//浅拷贝
    let len = array.length;
    let addCount = addElements.length;

    // 处理参数边缘化的情况
    startIndex = computedStartIndex(startIndex, len);
    delCount = computedDelCount(startIndex, delCount, len);

    // 获取删除元素,并添加到新数组中
    let delArr = new Array(delCount).fill(null);
    sliceDelElements(delArr, array, startIndex);
    // 移动原数组
    removeArr(array, startIndex, delCount, addCount);
    // 添加新元素到原数组中
    for (let i = 0; i < addCount; i++) {
        arr[startIndex + i] = addElements[i];
    }

    array.length = len -delCount + addCount;
    return delArr;

}

然后就是分别给出上面四点的具体实现代码~

1. 处理startIndex,delCount边缘化的情况

(例如初始下标小于0或者大于数组长度,删除数量小于0或删除数量比能删的数量多的情况)

const computedStartIndex = function (startIndex, len) {
    //startIndex为负数
    if (startIndex < 0) {
        return startIndex + len > 0 ? startIndex + len : 0;
    }
    //startIndex>len 不删除了
    return startIndex > len ? len : startIndex;
}

const computedDelCount = function (startIndex, delCount, len) {
    //delCount没写,默认删除后面所有
    if (typeof delCount === "undefined") {
        return len - startIndex;
    }
    //delCount太大
    else if (delCount > len - startIndex) {
        return len - startIndex;
    }
    //delCountIndex为负数
    else if (delCount < 0) {
        return 0;
    }
    return delCount;
}

2. 获取删除元素,并添加到新数组中

(这个比较简单,遍历完事~)

const sliceDelElements = function (delArr, array, startIndex) {
    for (let i = 0; i < delArr.length; i++) {
        delArr[i] = array[startIndex + i]
    }
    return delArr;
}

3. 移动原数组

(主要考虑三种情况:删除数量 大于/小于/等于 添加数量 ;这个关系到原数组是向前还是向后移动了

const removeArr = function (array, startIndex, delCount, addCount) {
    //删除数量小于增加数量,数组向后移动
    if (delCount < addCount) {
        // 向后移动几位 addCount - delCount
        for (let i = array.length; i >= startIndex + delCount; i--) {
            let fromIndex = i;
            let toIndex = i + addCount - delCount;
            arr[toIndex] = arr[fromIndex];
        }
    }
    // 删除数量大于增加数量,数组向前移动
    else if (delCount > addCount) {
        // 向前移动 delCount - addCount 位
        for (let i = startIndex + delCount; i < array.length; i++) {
            let fromIndex = i;
            let toIndex = i - delCount + addCount;
            arr[toIndex] = arr[fromIndex];
        }
        // 删除冗余元素
        for (let i = array.length - 1; i >= array.length - delCount + addCount; i--) {
            delete array[i]
        }
    }
    // 删除数量等于增加数量 ,数组不变
    else {
        return;
    }
}

4. 添加新元素到原数组中

(由于上一步“移动原数组”,已经给新元素腾好位了,所以这一步也只是简单的遍历啦
这一部分的代码写在“大纲”里面了
最后检验一下~(可以自己运行一遍试试看,结果就不贴了)

let arr = [10, 20, 30, 40, 50];
let arr1 = arr.mySplice(-2);
console.log(arr1);
console.log(arr)

ps:这里参考了这篇文章,如果看到这里还整不明白实现splice的思路,可以点进去看看~

reduce方法

数组中用来迭代遍历每一项的。可以把每一次处理的结果都拿到,在第一次处理的基础上,进行二次处理……直到数组遍历完成

reduce(callback(result,item,currentIndex,arr),value)
和callback的同级别中,如果传递了value值,则第一次执行callback,result存储的参数信息value的值。同时item迭代的是数组的第一项;如果不传value,result是数组第一项,同时item是数组第二项(注:value可选)

value没有传值的情况:

let arr = [10,20,30,40,50];
let add = arr.reduce((result,item,i)=>{
    console.log(result,item,i);//10,20,1
    //  这里result是数组第一项,item是数组第二项,i为当前item的下标
})

value有传值的情况:

let arr = [10,20,30,40,50];
let add = arr.reduce((result,item,i)=>{
    console.log(result,item,i);//0 10 0
    // 这里result存储参数value的值,item是数组第二项,i为当前item的下标
},0)

这个函数经常被人们用来当作“累加器”,因为数组会迭代每一项,并且每一次处理的结果,都会存储到result里面,下次迭代的时候,可以对上一次处理的结果,进行二次处理

例如这个简单的累加

let arr = [10,20,30,40,50];
let add = arr.reduce((result,item,i)=>{
    return result + item;
    //第一次迭代:result:10 item:20 返回结果:30(10+20)
    //第二次迭代:result:30 item:30 返回结果:60(30+30)
    // 。。。
})
console.log(add);//150

开始实现

彻底了解了reduce这个方法后,开始来捋捋思路了

  1. 方法对原数组是不产生影响的(所以一开始就要把数组拷贝一份)
  2. value有无传值的影响(有传值,item是第一项,index=0 ;没有传值,则item是数组的第2项,index=1
  3. 如果原数组只有一项,且没有传值的情况(一般没有传值的话,item是数组第二项,既然没有第二项了,那么就直接返回result

下面直接贴代码了

function myReduce(arr,callback,init){
    //这个是为了不对原数组产生影响
    arr = arr.slice(0)
    // 判断有没有传递初始值
    // 这里做了优化,只有第一次迭代的时候需要判断init,后面就不需要了
    let result = init;
    // 有传值,item是第一项,index=0 
    for(let i = 0;i<arr.length;i++){
        // 没有传值,则item是数组的第2项,index=1  init===>undefined
        if(init === undefined && i === 0){
            result = arr[0];
            // 如果item只有一项,直接返回了
            let item = arr[1],
                index = 1;
            if(!item) return result;
            result = callback(result,item,index);
            i++;
            continue;
        }
        let item = arr[i],
            index = i;
        result = callback(result,item,index);     
    }
    return result;
}

测试!

console.log("======没有传值======")
let result1 = myReduce(arr,function(result,item,index){
    console.log(result,item,index)
    return result +item;
})
console.log(result1)
//=====
console.log("======有传值======")
//=======
let result2 = myReduce(arr,function(result,item,index){
    console.log(result,item,index)
    return result +item;
},0)
console.log(result2)

希望我把思路给你捋明白了!能看到这里的你,一定很棒!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值