• 手写数组方法之会改变原数组方法


    pop

    用法

    pop 方法可以弹出数组最后一个元素,并将其作为返回值

    const arr = [1,2,3]
    arr.pop()                // 返回移除的元素 5,数组变成 [1,2,3,4] 

    实现

    Array.prototype.myPop = function(){
        let arr = this
        let returnValue = arr[arr.length - 1]
        arr.length--
        return returnValue
    }

    push

    用法

    push 方法可以往数组末尾添加任意多个元素,并将数组长度作为返回值:

    const arr = [1,2,3]
    arr.push(4,5)            // 返回最终的数组长度 5,数组变成 [1,2,3,4,5]

    实现

    Array.prototype.myPush = function(...args){
        let arr = this
        for(let el of args){
           arr[arr.length] = el
        }
        return arr.length
    }

    shift

    用法

    shift 方法可以从数组头部弹出一个元素,并将其作为返回值:

    const arr = [3,4,5]
    arr.shift()              // 返回移除的元素 1,数组变成 [2,3,4,5]

    实现

    Array.prototype.myShift = function(){
        let arr = this
        let returnValue = arr[0]
        for(let i = 1;i < arr.length;i++){
            arr[i-1] = arr[i]
        }
        arr.length--
        return returnValue
    }

    unshift

    用法

    unshift 方法可以往数组头部添加任意多个元素,并将数组长度作为返回值:

    const arr = [3,4,5]
    arr.unshift(1,2)         // 返回最终的数组长度 5,数组变成 [1,2,3,4,5]

    实现

    Array.prototype.myUnshift = function(...args){
        let arr = this
        if(args.length > 0){
            let len1 = arr.length,len2 = args.length
            // k 代表数组最后一个元素的下标
            let k = len1 + len2 - 1
            for(let i = len1 - 1;i >= 0;i--){
                arr[k--] = arr[i]
            }
            for(let i in args){
                arr[i] = args[i]
            }   
        }    
        return arr.length
    }

    reverse

    用法

    reverse 将原数组进行反转,最终返回原数组

    [1,2,3].reverse()           // [3,2,1]

    实现

    Array.prototype.myReverse = function(){
        let arr = this
        let k = arr.length - 1
        for(let i = 0;i < Math.floor(arr.length/2);i++){
            let temp = arr[i]
            arr[i] = arr[k]
            arr[k--] = temp
        }
        return arr
    }

    sort

    用法

    reverse 也算是一种排序方法,但显然它不够灵活,于是有了 sort 方法。

    • sort 不接受参数或者接受的参数为 undefined 时,默认的排序规则是:将每个元素转化为字符串,再将它们按照 Unicode 编码从小到大排序。其中,null 会转化为 "null"undefined 固定排在数组最后
    • sort 接受参数且为排序函数的时候,按照排序函数的规则排序:若函数返回值为负数,则第一个参数排在第二个参数前面,若为正数,则在它后面,若为 0 则位置不变
    const arr = [1,2,5,10]   
    // 没有传入函数,会对每个元素调用 toString,比较字符的 unicode 编码,因此 "10"<"2"
    arr.sort()                  // [1,10,2,5] 
    // 传入比较函数,从小到大排序
    arr.sort((a,b) => ab?1:0)     // [1,2,5,10]
    arr.sort((a,b) => a-b)                // [1,2,5,10]
    // 传入比较函数,从大到小排序
    arr.sort((a,b) => a>b?-1:a 
    

    实现

    Array.prototype.mySort = function(...args){
        let arr = this   
        // 判断规则,判断 x 是否应该放在 y 的前面
        function shouldBefore(x,y){
            // 如果没传参或者传了 undefined
            if(args.length == 0 || args.length != 0 && typeof args[0] === 'undefined'){
                return String(x) < String(y)    
            } 
            // 如果传函数
            else {
                let fn = args[0]
                return fn(x,y) < 0 ? true : false
            }
        }
        // 如果传参但是没传函数或者 undefined
        if(typeof args[0] != 'function' && typeof args[0] != 'undefined'){
            throw new TypeError("The argument msut be undefined or a function")
        } else {
            for(let i = 0;i < arr.length - 1;i++){
                for(let j = 0;j < arr.length - 1 - i;j++){
                    if(shouldBefore(arr[j+1],arr[j])){
                        // 两数交换
                        let temp = arr[j]
                        arr[j] = arr[j+1]
                        arr[j+1] = temp                  
                    }
                }
            }
        }
        return arr
    }

    splice

    用法

    splice 可以做三种事:删除元素、添加元素、替换元素。

    • 接受三个参数:开始操作的位置 start、删除的元素个数num ,以及添加的元素 item1、item2、...
    • start 可以是正数或者负数。如果是正数且超过数组长度,则无视删除操作,直接把需要添加的元素添加到数组末尾;如果是负数,且负数绝对值小于数组长度,则将负数与长度相加作为 start,否则将 0 作为 start
    • num 可以是正数或者负数。如果没有传 num,或者 num 是正数且超过 start 往后的元素个数(包含 start),则将 start 和它后面所有元素删除;如果 num 是 0 或者负数,则不删除任何元素
    • 这个方法会修改到原数组,且最终返回一个包含被删除元素的数组,或者空数组
    const arr = [1,2,3,4,5]
    
    // 删除:在索引1这里操作,删除2个元素
    arr.splice(1,2)                 // 返回 [2,3],arr 变成 [1,4,5]
    
    // 添加:在索引1这里操作,删除0个元素,添加2个元素(注意是插入到索引1前面,不是后面)
    arr.splice(1,0,"a","b")          // 返回 [],arr 变成 [1,"a","b",2,3,4,5]
    
    // 替换:删除+添加就是替换
    arr.splice(1,2,"a","b")          // 返回 [1,"a","b",4,5]

    实现

    Array.prototype.mySplice = function(...args){
        let arr = this
        let len = arr.length
        let res = []
        function computeStart(start){
            return start >= 0 ? start : Math.abs(start) < len ? start + len : 0    
        }
        function computeDeleteNum(args,start){
            return args.length < 2 ? 
                len - start : args[1] > 0 ? Math.min(args[1],len - start) : 0   
        }
        function sliceArray(arr,separator){
            let arr1 = [],arr2 = []
            for(let i = 0;i < arr.length;i++){
                i < separator ? arr1.push(arr[i]) : arr2.push(arr[i])
            }
            // 清空原数组
            arr.length = 0
            return [arr1,arr2]
        }
        // 如果有传参数
        if(args.length > 0){
            // 确定 start 和 deleteNum 的取值
            let start = computeStart(args[0])
            let deleteNum = computeDeleteNum(args,start)        
            // 如果 start 已经大于等于数组长度,则只需关注是否有添加元素,无需进行后续操作        
            if(start >= len){
                if(args.length > 2){
                    for(let i = 2;i < args.length;i++){
                        arr.push(args[i])
                    }   
                }
            } else {
                // 以 start 为界分割原数组
                let [arr1,arr2] = sliceArray(arr,start)
                // 如果有需要,就删除元素
                if(deleteNum != 0){
                    for(let i = 0;i < deleteNum;i++){
                        // 把删除的元素放进返回的 res 数组中
                        res.push(arr2.shift())                
                    }
                }
                // 如果有需要,就添加元素
                if(args.length > 2){
                    for(let i = 2;i < args.length;i++){
                        arr1.push(args[i])
                    }
                }    
                const tempArr = [...arr1,...arr2]
                for(let el of tempArr){
                    arr.push(el)
                }
            }
        }
        return res
    }

    PS:个人感觉 splice 的实现算是这几个里比较麻烦的,因为需要考虑很多情况。上面的代码已经通过 MDN 的全部测试用例,但还有不少需要优化的地方。

    fill

    用法

    用某个值替换(填充)数组中的全部值或者部分值:

    • 接受三个参数:toFillbegin 和 endtoFill 表示填充元素,不传则为 undefined;begin 表示开始填充位置,默认从数组第一个元素开始;end 表示结束填充位置(该位置不填充),默认等于数组长度
    • begin 可以是正数或者负数。如果是负数且绝对值小于数组长度,则将其与长度相加作为 begin,若大于数组长度,则取 0 作为 begin
    • end 可以是正数或者负数,如果是正数且超过数组长度,则取数组长度作为 begin;如果是负数且绝对值小于数组长度,则将其与长度相加作为 end
    const arr = [0,0,0,0,0]
    arr.fill(5)                 // [5,5,5,5,5]
    arr.fill(5,2)               // [0,0,5,5,5]
    arr.fill(5,2,4)             // [0,0,5,5,0] 
    arr.fill(5,-3,-1)           // [0,0,5,5,0]  负值索引 => 负值索引 + 数组长度
    arr.fill(5,-100,-90)        // 越界,无效
    arr.fill(5,100,90)          // 越界,无效
    arr.fill(5,4,2)             // 反向,无效

    实现

    Array.prototype.myFill = function(toFill,begin = 0,end = this.length){
        let arr = this
        let len = arr.length
        begin = begin >= 0 ? begin : Math.abs(begin) < len ? begin + len : 0
        end = end >= 0 ? Math.min(end,len) : Math.abs(end) < len ? end + len : end
        for(;begin < end;begin++){
            arr[begin] = toFill
        }
        return arr
    }

    copyWithin

    用法

    复制数组的某个部分,顶替数组中的某些元素:

    • 接受三个参数,target 表示开始操作的位置,begin 和 end 共同决定需要复制的范围(不包括 end
    • 用范围内的所有元素去覆盖从 target 开始的元素
    const arr = [0,1,2,3,4,5,6,7,8]
    arr.copyWithin(4)                   // [0,1,2,3,0,1,2,3,4]   缺省范围为整个数组
    arr.copyWithin(4,7)                 // [0,1,2,3,7,8,6,7,8]
    arr.copyWithin(4,6,9)               // [0,1,2,3,6,7,8,7,8] 
    
    // 对于负值索引、反向索引和越界索引的处理,和 fill 方法类似

    实现

    Array.prototype.myCopyWithin = function(target = 0,begin = 0,end = this.length){
        let arr = this
        let len = arr.length
        let copyArr = []
        let m = 0,n = 0
        target = target >= 0 ? target : Math.abs(target) < len ? target + len : 0
        begin = begin >= 0 ? begin : Math.abs(begin) < len ? begin + len : 0
        end = end >= 0 ? Math.min(end,len) : Math.abs(end) < len ? end + len : end
        // 把需要复制的元素放到 copyArr 数组中
        for(;begin < end;begin++){
            copyArr[m++] = arr[begin]
        }
        let _len = copyArr.length < len - target ? target + copyArr.length : len
        // 用 copyArr 数组从 target 开始覆盖原数组
        for(;target < _len;target++){
            arr[target] = copyArr[n++]
        }
        return arr
    }
    
  • 相关阅读:
    『python爬虫』xpath变化导致无法找到指定元素(持续更新中~)
    常用SQL语法总结
    Kotlin let run with apply also 关键字
    中学生物教学杂志中学生物教学杂志社中学生物教学编辑部2022年第15期目录
    CAS号:60535-02-6,二肽Met-Trp
    LiveMedia视频中间件支持GB35114的设备接入
    postgresql|数据库|提升查询性能的物化视图解析
    ubuntu莫名的 系统出现文件系统只读
    【吞噬星空】爽翻,徐欣喜提永恒之体,罗峰秒杀败类,阿特金磕头认错
    伦敦银单位转换很简单
  • 原文地址:https://blog.csdn.net/qq_45272642/article/details/128180549