跳至主要內容

实现 Array 的原生方法

haneball大约 6 分钟JavaScriptTypeScript原生方法

forEach 方法

  • 参数有 callbackthisArg
  • 遍历所有元素并逐个执行 callback
type fnType<T> = (value: T, index: number, array: T[]) => void

interface Array<T> {
    myForEach(callback: fnType<T>, thisArg?: any): void
}

Object.defineProperty(Array.prototype, 'myForEach', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myForEach<T>(this: T[], callback: fnType<T>, thisArg?: any) {
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            callback.call(thisArg, this[i], i, thisArg)
        }
    }
})

map 方法

  • 参数有 callbackthisArg
  • 返回一个数组,由原数组每个元素调用 callback 的返回值组成
type fnType<T> = (value: T, index: number, array: T[]) => unknown

interface Array<T> {
    myMap(callback: fnType<T>, thisArg?: any): unknown[]
}

Object.defineProperty(Array.prototype, 'myMap', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myMap<T>(this: T[], callback: fnType<T>, thisArg?: any): unknown[] {
        const result = new Array<unknown>()
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            result.push(callback.call(thisArg, this[i], i, this))
        }

        return result
    }
})

filter 方法

  • 参数有 callbackthisArg
  • 返回一个数组,其各个元素均符合 callback 的测试条件
type fnType<T> = (value: T, index: number, array: T[]) => unknown

interface Array<T> {
    myFilter(callback: fnType<T>, thisArg?: any): T[]
}

Object.defineProperty(Array.prototype, 'myFilter', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myFilter<T>(this: T[], callback: fnType<T>, thisArg?: any): T[] {
        const result = new Array<T>()
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            callback.call(thisArg, this[i], i, this) && result.push(this[i])
        }

        return result
    }
})

every 方法

  • 参数有 callbackthisArg
  • 若所有元素都符合 callback 的条件,返回 true,否则返回 false
type fnType<T> = (value: T, index: number, array: T[]) => unknown

interface Array<T> {
    myEvery(callback: fnType<T>, thisArg?: any): boolean
}

Object.defineProperty(Array.prototype, 'myEvery', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myEvery<T>(this: T[], callback: fnType<T>, thisArg?: any): boolean {
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            if (!callback.call(thisArg, this[i], i, this)) return false
        }

        return true
    }
})

some 方法

  • 参数有 callbackthisArg
  • 若至少有一个元素符合 callback 的条件,返回 true,否则返回 false
type fnType<T> = (value: T, index: number, array: T[]) => unknown

interface Array<T> {
    mySome(callback: fnType<T>, thisArg?: any): boolean
}

Object.defineProperty(Array.prototype, 'mySome', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function mySome<T>(this: T[], callback: fnType<T>, thisArg?: any): boolean {
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            if (callback.call(thisArg, this[i], i, this)) return true
        }

        return false
    }
})

reduce 方法

  • 参数有 callbackinitial
  • 以上一次元素的计算结果作为 callback 的参数,直到最后一个元素并返回最终结果
  • initial 不为 undefined,以 initial 作为初始值从索引为 0 的元素开始计算,否则以索引为 0 的元素作为初始值从索引为 1 的元素,开始计算
  • 返回最终计算结果
type fnType<T> = (previous: T, current: T, currentIndex: number, array: T[]) => T

interface Array<T> {
    myReduce(callback: fnType<T>, initial?: T): T
}

Object.defineProperty(Array.prototype, 'myReduce', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myReduce<T>(this: T[], callback: fnType<T>, initial?: T): T {
        let [start, result] = typeof initial === 'undefined' ? [1, this[0]] : [0, initial]

        for (let i = start; i < this.length; i++) {
            result = callback(result, this[i], i, this)
        }

        return result
    }
})

reduceRight 方法

  • 参数有 callbackinitial
  • 以上一次元素的计算结果作为 callback 的参数,直到最后一个元素并返回最终结果
  • 与 reduce 方法类似,但从数组尾开始计算
  • 返回最终计算结果
type fnType<T> = (previous: T, current: T, currentIndex: number, array: T[]) => T

interface Array<T> {
    myReduceRight(callback: fnType<T>, initial?: T): T
}

Object.defineProperty(Array.prototype, 'myReduceRight', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myReduceRight<T>(this: T[], callback: fnType<T>, initial?: T): T {
        let [start, result] = typeof initial === 'undefined' ? [this.length - 2, this[0]] : [this.length - 1, initial]

        for (let i = start; i >= 0; i--) {
            result = callback(result, this[i], i, this)
        }

        return result
    }
})

find 方法

  • 参数有 callbackthisArg
  • 返回第一个符合 callback 条件的元素
type fnType<T> = (element: T, index: number, array: T[]) => unknown

interface Array<T> {
    myFind(callback: fnType<T>, thisArg?: any): T | undefined
}

Object.defineProperty(Array.prototype, 'myFind', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myFind<T>(this: T[], callback: fnType<T>, thisArg?: any): T | undefined {
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            if (callback.call(thisArg, this[i], i, this)) return this[i]
        }

        return undefined
    }
})

findIndex 方法

  • 参数有 callbackthisArg
  • 返回第一个符合 callback 条件的元素的索引
type fnType<T> = (element: T, index: number, array: T[]) => unknown

interface Array<T> {
    myFindIndex(callback: fnType<T>, thisArg?: any): number
}

Object.defineProperty(Array.prototype, 'myFindIndex', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myFindIndex<T>(this: T[], callback: fnType<T>, thisArg?: any): number {
        thisArg = thisArg || this

        for (let i = 0; i < this.length; i++) {
            if (callback.call(thisArg, this[i], i, this)) return i
        }

        return -1
    }
})

fill 方法

  • 参数有 callbackstartend
  • value 填充数组从 startend 前的所有元素
  • 返回修改后的数组
interface Array<T> {
    myFill(value: T, start?: number, end?: number): T[]
}

Object.defineProperty(Array.prototype, 'myFill', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myFill<T>(this: T[], value: T, start: number = 0, end?: number): T[] {
        end = end || this.length

        for (let i = start; i < end; i++) {
            this[i] = value
        }

        return this
    }
})

includes 方法

  • 参数有 valuestart
  • 若数组包含 value,返回 true,否则返回 false
interface Array<T> {
    myIncludes(value: T, start?: number): boolean
}

Object.defineProperty(Array.prototype, 'myIncludes', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myIncludes<T>(this: T[], value: T, start: number = 0): boolean{
        for (let i = start; i < this.length; i++) {
            if (this[i] === value) return true
        }

        return false
    }
})

join 方法

  • 参数有 separator
  • 返回一个以 separator 作为分隔符连接各个元素的字符串
interface Array<T> {
    myJoin(separator?: string): string
}

Object.defineProperty(Array.prototype, 'myJoin', {
    enumerable: false,
    writable: false,
    configurable: false,
    value: function myJoin<T>(this: T[], separator: string = ','): string {
        let result = `${this[0]}`

        for (let i = 1; i < this.length; i++) {
            result += `${separator}${this[i]}`
        }

        return result
    }
})