JavaScript数组原生方法还不懂?进来带你过一遍

322 阅读4分钟

JavaScript原生方法

简介

我们平时在写代码的时候会用到JavaScript自带的许多原生方法,如果我们不知道它们内部是怎么实现的,那么就会大大增加使用困惑。

本篇会带领我们搞懂原生方法使用的前提下,并且自己实现该方法。

1. JavaScript数组

1. forEach

原生

遍历数组

这是我们经常用到的遍历数组原生函数

let arr = [8, 1, 6, 7, 5, 9, 10]

arr.forEach((value,index,arr)=>{
    console.log("当前值为",value);	// 8,1,6,7,5,9,10
    console.log("当前索引为",index);	// 0,1,2,3,4,5,6
    console.log("传进来的数组为",arr);	// [8, 1, 6, 7, 5, 9, 10]
})

手写

Array.prototype.myforEach = function (callback) {
    for (let i = 0; i < this.length; i++) {
        callback(this[i], i, this)
    }
}

他的内部是用for循环实现的,你可能会问那为什么不直接用for循环遍历而是要用forEach呢,因为方便啊!

2. map

原生

将返回值添加到新数组中并返回,新数组和原数组长度一致。

let arr = [9, 1, 6, 7, 5, 9, 10]

let newArr = arr.map((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value * 10;
})

Console.log(newArr)	// [90,10,60,70,50,90,100]

手写

Array.prototype.myMap = function (callback) {
    const res = []
    for (let i = 0; i < this.length; i++) {
        // 不管真和假,全部push进新数组,所以才导致 '新数组和原数组长度一致'
        res.push(callback(this[i], i, this))
    }
    return res
}

3. filter

原生

遍历数组,如果返回值为真,将当前元素添加到新数组

let arr = [9, 1, 6, 7, 5, 9, 10]

let  newArr = arr.filter((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value > 9;
})

console.log(newArr);	// [10]

手写

Array.prototype.myFilter = function (callback) {
    const res = []
    for (let i = 0; i < this.length; i++) {
        // &&:短路运算符,当第一个条件为false时后面的 res.push(this[i]) 不会运行
        callback(this[i], i, this) && res.push(this[i]) 
    }
    return res
}

这里经常有很多人将mapfilter函数认为功能一致,但是不是这样的,我们看它们内部代码就知道map是将返回值添加到新数组里。而filter是通过判断当前返回值是否为true,如果为true才添加当前值进新数组。

我教你们怎么分辨它们,filter单词本就有 '过滤器' 的含义,所以它是负责过滤不满足条件的元素,而过滤条件是你的返回值,记住,它只是过滤元素,而不改变原本的元素。如果你的数组为[1,2,3,4],你用filter返回的新数组中如果有值,那么值一定是[1,2,3,4]中存在的。

map单词有 '地图' 的含义,它只照着你的 '地图'(返回值)来重新push进新数组里,不管你给它的是任何东西。

4. every

原生

检测数组中的所有元素是否都满足指定条件,当有一个元素不符合要求时停止循环并返回false

let arr = [9, 1, 6, 7, 5, 9, 10]

let newArr = arr.every((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value > 1;	// 所有元素都需要大于1
})

console.log(newArr);	// false

手写

Array.prototype.myEvery = function (callback) {
    let flag = true
    for (let i = 0; i < this.length; i++) {
        flag = callback(this[i], i, this)
        if (!flag) break;
    }

    return flag
}

5. some

原生

检测数组中的所有元素是否有一个元素满足指定条件,当有一个属性符合要求时停止循环并返回true

let arr = [9, 1, 6, 7, 5, 9, 10]

let newArr = arr.some((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value = 9;
})

console.log(newArr);	// true

手写

Array.prototype.mySome = function (callback) {
    let flag = false
    for (let i = 0; i < this.length; i++) {
        flag = callback(this[i], i, this)
        if (flag) break
    }

    return flag
}

这里又要分辨一下everysome的区别了。

every单词有 '每一个' 的含义,必须所有都满足条件才返回true,否则不讲道理就返回false

some单词有 '一些' 的含义,当有一个满足条件我就给你通过,如果你一个都不满足那我也没办法只能返回false

6. reduce

原生

可用于数组求和,它的索引是从1开始的。

// 第一回合:reduce函数如果没有初始值则为数组第一个值,goValue为数组第二个值
// 第二回合:value为上一回合返回的值,govalue为数组第三个值,以此类推。
let arr = [9, 2, 6, 7, 5, 9, 10]

let newArr = arr.reduce((value, goValue, index) => {
    console.log("当前值为", value);
    console.log("下一个值为", goValue);
    console.log("当前索引为", index);

    return value + goValue;
})

console.log(newArr);	// 48
console.log(arr.reduce(fn..., 2));	// 50	 初始值为2,那么第一回合vakue为2	

手写

Array.prototype.myReduce = function (callback, ...args) {
    let start = 0, pre
    if (args.length) {
        pre = args[0]
    } else {
        pre = this[0]
        start = 1
    }
    for (let i = start; i < this.length; i++) {
        pre = callback(pre, this[i], i, this)
    }
    return pre
}

7. findIndex

原生

查找指定值的索引位置,如果未找到返回-1

let arr = [9, 2, 6, 7, 5, 9, 10]

let newArr = arr.findIndex((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value == 5;
})

console.log(newArr);	// 4

手写

Array.prototype.myFindIndex = function (callback) {
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            return i
        }
    }
    return -1
}

8. find

原生

查找指定值的,如果未找到返回undefined

let arr = [9, 2, 6, 7, 5, 9, 10]

let newArr = arr.find((value, index, arr) => {
    console.log("当前值为", value);
    console.log("当前索引为", index);
    console.log("传进来的数组为", arr);

    return value == 5;
})

console.log(newArr);	// 5

手写

Array.prototype.myFind = function (callback) {
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            return this[i]
        }
    }
    return undefined;
}

9. fill

原生

填充替换数组中的元素

let a = [1, 2, 3, 4, 5, 6]

let newA = a.fill("x",2,5)	// [1, 2, 'x', 'x', 'x', 6]

// 第一个参数为要替换的值,第二个为开始位置的索引,第三个为到哪个元素结束,如果找不到该元素就替换到结尾

手写

Array.prototype.myFill = function (value, start = 0, end) {
    end = end || this.length
    for (let i = start; i < end; i++) {
        this[i] = value
    }
    return this
}

10. includes

原生

检测数值是否包含某个元素,它和some不同点就是它可以检测NaN

let a = [1, 2, 3, 4, 5, 6, NaN]

let newA = a.includes(NaN2)	// true

// 第一个参数为要寻找的值,第二个值为从哪个索引位置开始查找,如果为负数就全局查找

手写

Array.prototype.myIncludes = function (value, start = 0) {
    if (start < 0) start = this.length + start
    const isNaN = Number.isNaN(value)
    for (let i = start; i < this.length; i++) {
        if (this[i] === value || Number.isNaN(this[i]) === isNaN) {
            return true
        }
    }
    return false
}

11. join

原生

将数组以指定分隔符分隔为字符串

let a = [1, 2, 3, 4, 5, 6, NaN]

let newA = a.join(",")	// 1,2,3,4,5,6,NaN

// 分隔符如果省略,元素自动用逗号分隔

手写

Array.prototype.myJoin = function (s = ',') {
    let str = ''
    for (let i = 0; i < this.length; i++) {
        str = i === 0 ? `${str}${this[i]}` : `${str}${s}${this[i]}`
    }
    return str
}

12. flat

原生

将多维数组拍平

let a = [1, 2, 3, [30, 40, [50, 60]], 4, 5, 6, NaN, [10, 20]]

let newA = a.flat(2)	// [1, 2, 3, 30, 40, 50, 60, 4, 5, 6, NaN, 10, 20]

// 不传参数默认拍平一层

手写

Array.prototype.myFlat = function () {
    let arr = this
    while (arr.some(item => Array.isArray(item))) {
        arr = [].concat(...arr)
    }
    return arr
}