前端手写题系列之:数组的那些方法

52 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

数组的API:forEach、map、filter、reduce、push、pop

笔者为了方便自己记忆,把这些方法大概抽离出了一个框架,这样子,写的时候,只需根据API的特性,向其中填入代码。

Array.prototype.arr = function(callback, thisArg) {
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  for (let i = 0; i < len; i++) {
    if (i in O) {
      callback.call(thisArg, O[i], i, O)
    }
  }
}

首先,判断对一些异常情况做处理。对数组的每一个数据做一个遍历,使用传入的回调函数进行处理。

Array.prototype.forEach()

思路:对传入的数字,每一个都是用回调函数进行处理

Array.prototype.forEach = function (callback, thisArg) {
  console.log('forEach')
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  for (let i = 0; i < len; i++) {
    if (i in O) {
      callback.call(thisArg, O[i], i, O)
    }
  }
}

Array.prototype.map()

思路:

  1. map 会返回一个处理之后的数组,所以需要 result 数组作为返回值
  2. result 数组中的值,就等于回调函数返回来的值
Array.prototype.map = function (callback, thisArg) {
  console.log('map')
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  const result = []
  for (let i = 0; i < len; i++) {
    if (i in O) {
      result[i] = callback.call(thisArg, O[i], i, O)
    }
  }
  return result
}

Array.prototype.filter()

思路:

  1. filter 会返回一个处理之后的数组,所以需要 result 数组作为返回值
  2. 符合回调函数的,则依次加入到数组中
Array.prototype.filter = function (callback, thisArg) {
  console.log('filter')
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  const result = []
  let resultLen = 0
  for (let i = 0; i < len; i++) {
    if (i in O) {
      if (callback.call(thisArg, O[i], i, O)) {
        result[resultLen++] = O[i]
      }
    }
  }
  return result
}

Array.prototype.reduce()

思路:

  1. reduce 会返回一个处理之后的数组,所以需要 result 变量作为返回值
  2. 将 callback 处理之后的函数值赋值给 result 变量
  3. 判断当初始值为0的时候,需要从传入的数组中获取到一个值,做为初始值
  4. 复用 i 变量
Array.prototype.reduce = function (callback, initValue) {
  console.log('reduce')
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  let result = initValue
  let i = 0
  if (initValue === undefined) {
    for (; i < len; i++) {
      if (i in O) {
        result = O[i]
        i++
        break
      }
    }
  }
  for (; i < len; i++) {
    if (i in O) {
      result = callback.call(undefined, result, O[i], i, O)
    }
  }
  return result
}

思路:

  1. push 会返回一个处理之后的数组长度,所以需要 result 变量作为返回值
  2. 在处理之前,需要判断长度是否超出最大值
  3. 遍历传入的参数,添加到原先的数组中
Array.prototype.push = function (...items) {
  console.log('push')
  if (this === undefined) {
    throw new Error('error')
  }
  const O = Object(this)
  const len = O.length >>> 0
  const argsCount = items.length >>> 0
  if (len + argsCount > 2 ** 53 - 1) {
    throw new Error('error')
  }
  let result = len + argsCount
  O.length = result
  for (let i = 0; i < argsCount; i++) {
    O[len + i] = items[i]
  }
  return result
}

Array.prototype.pop()

思路:

  1. pop 会返回数组中最后一个数据,所以需要 result 变量作为返回值
  2. 在处理之前,需要判断长度是否为 0
  3. 减去数组长度
  4. 获取数组最后一个数据,作为返回值
  5. 删除该数据
Array.prototype.pop = function () {
  console.log('pop')
  if (this === undefined) {
    throw new Error('error')
  }
  const O = Object(this)
  let len = O.length >>> 0
  if (len === 0) {
    O.length = 0
    return undefined
  }
  len--
  let result = O[len]
  delete O[len]
  O.length = len
  return result
}