手撸Array数组原型方法

174 阅读4分钟

push

Array.prototype._push = function (...args) {
    let arr = this
    let l = arr.length
    let len = l + args.length

    let index = 0
    while (index < args.length) {
        arr[l + index] = args[index]
        index++
    }

    return len //push返回值是添加元素后数组的长度
}

pop

Array.prototype._pop = function () {
    let arr = this
    let l = arr.length
    let result
    if (l > 0) {
        result = arr[l - 1]
        arr.length--
    }
    return result
}

unshift

Array.prototype._unshift = function (...args) {
    let arr = this
    let l = arr.length
    let len = l + args.length

    let i = 1
    while (i <= l) {
        arr[len - i] = arr[l - i]
        i++
    }
    let j = 0
    while (j < args.length) {
        arr[j] = args[j]
        j++
    }

    return len //返回数组长度
}

shift

Array.prototype._shift = function () {
    let arr = this
    let result

    if (arr.length > 0) {
        result = arr[0]
        let index = 0
        while (index < arr.length - 1) {
            arr[index] = arr[index + 1]
            index++
        }
        arr.length--
    }

    return result
}

reverse

Array.prototype._reverse = function () {
    let arr = this

    if (arr.length > 1) {
        let l = 0;
        let r = arr.length - 1

        while (l < r) {
            [arr[l], arr[r]] = [arr[r], arr[l]]
            l++
            r--
        }
    }

    return arr
}

splice

Array.prototype._splice = function (s, n = Infinity, ...args) {
    let arr = this
    let result = []
    let left = []
    let right = []
    let temp

    if (s >= 0 && s < arr.length) { //限制删除的开始位置在0 - arr.length 之间(未考虑负数的情况))
        n = Math.min(n, arr.length - s)  // 限制最多只能删除数组的个数
        for (let i = 0; i < arr.length; i++) {
            if (i < s) {
                left.push(arr[i])
            } else {
                if (n > 0) {
                    result[result.length] = arr[s + result.length]
                    n--
                } else {
                    right.push(arr[i])
                }
            }
        }

        if (args.length > 0) {
            temp = [...left, ...args, ...right] // 拼接要添加的值
        } else {
            temp = [...left, ...right]
        }

        arr.length = temp.length // 修改原数组,将模版数组的值copy到原数组
        for (let i = 0; i < temp.length; i++) {
            arr[i] = temp[i]
        }
    }

    return result //返回删除的值
}

fill

Array.prototype._fill = function (val, start = 0, end = Infinity) {
    let arr = this
    let len = arr.length

    start = start < 0 ? Math.max(start + len, 0) : Math.min(start, len)

    end = end < 0 ? Math.max(end + len, start) : Math.min(end, len)

    while (start < end) {
        arr[start++] = val
    }

    return arr
}

以上是含有副作用的数组方法,使用后会改变数组本身,带有副作用的方法有:push、pop,unshift,shift,splice,reverse,sort,fill(如果还有其他的欢迎指出)


map

Array.prototype._map = function(cb){
    if(typeof cb !== 'function') {
        throw new TypeError(cb + ' is not a function')
    }

    let T
    let arr = this
    let len = arr.length
    let result = new Array(len)

    if(arguments.length > 1){ //map的的第二个参数为调用回调函数cb的this指向
        T = arguments[1]
    }

    let index = 0
    while(index<len){
        if(index in arr){ // 稀疏数组不做处理,例如[1,2,,,5],只处理下标为:0,1,4
            result[index] = cb.call(T,arr[index],index,arr) //回调函数接收3个参数(当前索引对应的值,索引,数组本身)
        }
        index++
    }

    return result
}

reduce

Array.prototype._reduce = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError(cb + ' is not a function')
    }

    let index, result
    let arr = this
    let len = arr.length

    index = 0
    if (arguments.length > 1) { //reduce第二个参数为初始值
        result = arguments[1]
    } else { // 如果没有传将取数组开头的第一个非稀疏值的元素
        while (index < len && !(index in arr)) { //例如[,,30,40,50],初始值为30,遍历就会从40开始,所以下标index会从3开始
            index++
        }
        if (index >= len) {
            throw Error('this is a empty array')
        }
        result = arr[index++]
    }

    while (index < len) {
        if (index in arr) {
            result = cb(result, arr[index], index, arr) // cb接受4个参数,1累计值,2数组当前值,3当前索引,4原数组
        }
        index++
    }

    return result
}

filter

Array.prototype._filter = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let T
    let arr = this
    let len = arr.length
    let result = []

    if (arguments.length > 1) {
        T = arguments[1]
    }

    let index = 0
    while (index < len) {
        if (index in arr) {
            if (cb.call(T, arr[index], index, arr)) {//当cb结果为true时添加值到result
                result.push(arr[index])
            }
        }
        index++
    }

    return result
}

find

Array.prototype._find = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let arr = this
    let len = arr.length
    let T = arguments[1]
    let result

    let index = 0
    while (index < len) {
        if (cb.call(T, arr[index], index, arr)) {
            return result = arr[index] //返回第一个满足条件的值
        }
        index++
    }

    return result
}

findIndex

Array.prototype._findIndex = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let arr = this
    let len = arr.length
    let T = arguments[1]
    let result = -1

    let index = 0
    while (index < len) {
        if (cb.call(T, arr[index], index, arr)) {
            return result = index //返回第一个满足条件的下标,一直未满足返回-1
        }
        index++
    }

    return result
}

some

Array.prototype._some = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let arr = this
    let len = arr.length
    let T = arguments[1]

    let index = 0
    while (index < len) {
        if (index in arr && cb.call(T, arr[index], index, arr)) { //检查数组中只要有一个满足条件的元素就返回true
            return true
        }
        index++
    }

    return false
}

every

Array.prototype._every = function (cb) {
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let arr = this
    let len = arr.length
    let T = arguments[1]

    let index = 0
    while (index < len) {
        if (index in arr) {
            if (!cb.call(T, arr[index], index, arr)) return false // 只要有一项不满足条件就返回false
        }
        index++
    }

    return true // 全部满足返回true
}

forEach

Array.prototype._forEach = function (cb) { //forEach执行后无法跳出循环,除非抛出一个异常,如果需要提前跳出建议使用其他遍历方法
    if (typeof cb !== 'function') {
        throw new TypeError((cb + ' is not a function'))
    }

    let arr = this
    let len = arr.length
    let T = arguments[1]

    let index = 0
    while (index < len) {
        if (index in arr) {
            cb.call(T, arr[index], index, arr)
        }
        index++
    }
}

flat

Array.prototype._flat = function () { // flat 是es10推出的,使用时要注意兼容性
    let arr = this

    function fn (arr) { //递归版
        return arr.reduce((acc, cur) => acc.concat(Array.isArray(cur) ? fn(cur) : cur), [])
    }

    return fn(arr)
}

// function flatDeep (arr) {  //循环版
//     let temp = [...arr]
//     let result = []

//     while (temp.length) {
//         let item = temp.pop()
//         if (Array.isArray(item)) {
//             temp.push(...item)
//         } else {
//             result.push(item)
//         }
//     }

//     return result.reverse()
// }


以上的方法部分参考[MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array)数组的polyfill