JavaScript手写数组API

374 阅读2分钟

JavaScript中的数组提供了很多原生方法,今天模拟实现一些常用的数组API(forEach,map,reduce,every,filter,find,indexOf,some)

1.forEach

  • 语法
    array.forEach(function(currentValue, index, arr), thisValue)
  • 代码简单实现
    Array.prototype._forEach = function (fn, thisValue) {
        let index = 0;
        let arr = thisValue || this;
        if (typeof fn !== 'function') {
            throw new TypeError(fn + 'is not a function')
        }
        while (index < arr.length) {
            if (index in arr) {
                fn.call (thisValue, arr[index], index, arr)
            }
            index ++
        }
    };
    
    let arr = [1, 3, 5, 7]
    arr._forEach((item, i , arr) =>{
        console.log('item:' + item + 'i:' + i)
    })
  • 支持 async/await
    arr._forEach(async v => {
        await fetch(v)
    })
    //上面的写法forEach做不到同步,程序不会等下一个循环中的异步完成再进行下一个循环。改下写法
    
    Array.prototype._forEach = async function (fn, thisValue) {
        let index = 0;
        let arr = thisValue || this;
        if (typeof fn !== 'function') {
            throw new TypeError(fn + 'is not a function')
        }
        while (index < arr.length) {
            if (index in arr) {
                try {
                    await fn.call(thisValue, arr[index], index, arr)
                } catch (e) {
                    console.log(e)
                }
            }
            index ++
        }
    }
    let arr = [1, 3, 5, 7]
  • map

map的实现和forEach大体类似,只是map会返回一个新的数组

  • 语法
    // 参数和forEach一样
    array.map(function(currentValue,index,arr),thisValue)
  • 代码实现
    Array.prototype._map = function(fn,thisValue){
        let arr = thisValue || this
        let index = 0
        let newArr = [];
        if(typeof fn !== 'function'){
            throw new TypeError(fn + 'is not function')
        }
        while(index<arr.length){
            if(index in arr){
                let result = fn.call(thisValue, arr[index], index, arr)
                newArr[index] = result //返回一个新数组
            }
            index++
        }
        return newArr
    }
    
    let arr = [1,3,5,7]
    let newArr = arr._map((item)=>{
        return item*3
    })
    console.log(newArr)
  • filter

filter一般用来筛选,会创建一个新的数组

  • 语法

    arr.fillter(function(currentValue,index,arr),thisValue)
    
  • 代码实现
Array.prototype._filter = function(fn, thisValue){
    let arr = thisValue || this
    let newArr = []
    
    if(typeof fn !== 'function'){
        throw new TypeError(fn + 'is not function')
    }
    if(arr.length>0){
        for(let i=0;i<arr.length;i++){
            if(fn.call(arr,arr[i],i,thisValue)){
                newArr.push(arr[i])
            }
        }
    }
    return newArr
}

let arr = [1,3,5,7]
let newArr = arr._filter((item)=>{
    return item>3
})

console.log(newArr)
  • reduce

reduce()接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算一个值。同时reduce()可以作为一个高阶函数,用于函数的compose.

  • 语法
    arr.reduce(function(total,currentValue,currentIndex,arr),initialValue)
  • 代码实现
    Array.protoType._reduce= function(fn,initialValue){
        let arr = this
        if(typeof fn !== 'function'){
            throw new TypeError(fn+ 'is not function')
        }
        if(!arr.length){
            return
        }
        let newArr = initialValue || 0
        for (let i = 0; i < arr.length; i ++){
            newArr = fn.call(arr,arr[i],i,arr)
        }
        return newArr
    }
    let arr = [1,3,5,7]
    function getSum(total,currentValue,currentIndex,arr){
        return total + currentValue
    }
    let newArr = arr._reduce(getSum,2)
    console.log(newArr)
  • slice

slice()可从已有数组中返回选定的元素,可提取字符串的某个部分,并返回新的字符串

  • 语法

array.slice(start,end)

  • 代码实现
Array.prototype._slice = function(start,end){
    let newArr = []
    for(let i=0; i< start+end; i++){
        newArr.push(this[i])
    }
    return newArr
}
let arr = ['A','B','C','D','E']

let newArr =arr._slice(2,4)

console.log(newArr) //['C','D','E']
  • splice

splice()用于添加或删除数组的方法,改变原数组

  • 语法
    arr.splce(index,howmany, item1,....,itemx)

  • 代码实现
    Array.prototype._splice= function(index,howmany=0){
        let arr = this
        let left = arr.slice(0,index) //截取左边的数组
        let right = arr.slice(index+ howmany,arr.length) //截取右边的数组
        let subArr = Array.prototype.slice.call(arguments,2) //截取参数里面需要添加的数组
        let result = []
        // 合并数组
        result = [...left,...right,...subArr]
        //改变this(改变原数组)
        for(let i = 0;i<result.length;i++){
            this[i] = result[i]
        }
        //返回删除的数据
        return this.slice(index,index+howmany)
    }
    let arr = ['a','b','c','d']
    let result =arr._splice(2,1,'e','f')
    console.log(result)// ['d']
    console.log(arr) //["a", "b", "d", "e", "f"]