【前端手撕】数组api

碎碎念

校内任务告一段落!(暂时

map

map**:映射** ------ 将原数组的每个元素映射成一个新值,组成新数组返回。

javascript 复制代码
Array.prototype.map = function(fn) {
    const res = []
    for (let i = 0; i < this.length; i++) {
        res.push(fn(this[i], i,this))
    }
    return res
}
  1. 使用map是arr.map这样用,所以this指向的是arr

  2. fn有三个参数是因为:

JavaScript 官方规定 Array.prototype.map 的回调函数必须接收这 3 个参数(按顺序):

  1. currentValue (当前元素的值) → 对应 this[i]

  2. index (当前元素的索引) → 对应 i

  3. array (调用 map 的原数组) → 对应 this

后续调用的时候传参可以只传部分,但底层map仍然是塞了三个实参,只不过fn只接收部分,忽略了其他。

Tip

几乎所有数组方法的回调函数都是传这三个参数:

方法 是否传 3 个参数 备注
forEach ✅ 是 只遍历,不返回新数组
map ✅ 是 返回新数组
filter ✅ 是 返回新数组(筛选)
some / every ✅ 是 返回布尔值(测试是否通过)
find / findIndex ✅ 是 查找元素或索引
reduce 特殊 回调是 (累加器, 当前值, 索引, 数组)4 个参数(因为多了一个累加器)

filter

filter() 是 JavaScript 数组原型上的一个内置方法。它的核心功能是根据指定条件(回调函数) ,从原数组中筛选出符合要求的元素,并组成一个新数组返回。即不破坏原数组。

javascript 复制代码
Array.prototype.filter = function(fn) {
    const res = []
    for (let i = 0; i < this.length; i++) {
        // 如果fn返回true(即满足条件),则把当前元素加到res数组中
        if (fn(this[i], i, this)) {
            res.push(this[i])
        }
    }
    return res
}

reduce

reduce 方法通过维护一个持续传递的累加器 (即上一次回调的返回值 res),将数组中的每个元素依次进行归并操作,最终将整个数组坍缩(归约) 为一个单一的结果值(可以是数字、对象或数组等)。

javascript 复制代码
Array.prototype.reduce = function(fn, initValue) {
    let res, start = 0
    if (arguments.length !== 1) {
        // 传了两个参数,有初始值
        res = initValue
    } else {
        // 只传了一个参数,从第一个元素开始
        res = this[0]
        start = 1
    }
    for (let i = start; i < this.length; i++) {
        // fn 执行完后返回一个新值,覆盖掉 res,继续下一次循环。
        res = fn(res, this[i], i, this)
    }
    return res
}

Tip

  1. 边界问题处理

如果数组是空的,并且用户没有传初始值, 按照这段代码:res = this[0] 会变成 undefinedstart = 1,循环不执行,最后返回 undefined。但真实的 JS 引擎在这种情况下会直接报错(TypeError: Reduce of empty array with no initial value)。因此可以在开头加一句:

javascript 复制代码
if (this.length === 0 && arguments.length === 1) {
  throw new TypeError('Reduce of empty array with no initial value');
}
  1. 为什么用 arguments.length 来判断是否有初始值,而不是直接用 if (initValue === undefined)

因为undefined是合法的初始值。例如:

javascript 复制代码
[1, 2].reduce(fn, undefined); 
  • 如果用 initValue === undefined 判断,会误以为没传初始值,导致程序逻辑错乱。

  • 如果用 arguments.length === 2 判断,就能精准识别:"用户确实传了第二个参数 (只是值恰好是 undefined)",从而正确地把 res 设为 undefined