如何快速记住手写数组方法的那些代码

作为大龄失业青年,在这个就业率低的时代,我也很无奈。

但是!!!!

八股文,该背还得背

那么

对于面试中的遇到的,手写数组的方法,比如 Array.forEach、Array.map、Array.filter、Array.reduce、Array.push、Array.pop

怎么能快速进行呢

特别提示⚠️:小菜鸟自嗨中,大佬可以麻烦退出,不浪费时间

Array.prototype.forEach()

为什么要先说 forEach,因为 forEach 是可以为后续的 Array.map、Array.filter、Array.reduce 搭建基础框架的。后续的三个代码都是在 forEach 上缝缝补补的


forEach 的使用

js 复制代码
[1, 2, 3, 4, 5, 6].forEach((item) => {
  console.log('item', item)
})

首先,我们需要做一些异常判断

js 复制代码
Array.prototype.forEach = function (callback, thisArg) {
  if (this === undefined) {
    throw new Error('error')
  }
  if (typeof callback !== "function") {
    throw new Error("error")
  }
}

之后,对于数组的遍历,需要用到for 循环

对,

就是那个原始的 for 循环

js 复制代码
Array.prototype.forEach = 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++) {
    // ...
  }
}

O 就是需要处理的对象,即这里的数组

接下来需要判断,当前这个元素,是不是在获取的对象上。如果是,那就用传入的回调函数去进行处理即可。

js 复制代码
Array.prototype.forEach = 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.map()

map 的使用

js 复制代码
const result = [1, 2, 3, 4, 5, 6].map((item) => item * 2)

按照我们之前说的,我们需要用到 forEach 的手写代码,改个名字

js 复制代码
Array.prototype.map = 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)
    }
  }
}

map 需要返回一个新数组,所以我们需要定义一个新数组,这个数组的长度和传入的数组长度一致。

js 复制代码
let result = new Array(len)

return result

新数组的数据,就是对原数组的数据进行处理

js 复制代码
result[i] = callback.call(thisArg, O[i], i, O)

好的,就多了这么三行代码,是的,组合一下

js 复制代码
Array.prototype.map = 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
  let result = new Array(len)
  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()

filter 的使用

js 复制代码
const result = [1, 2, 3, 4, 5, 6].filter((item) => item > 2)

框架抄下来,改个名字

js 复制代码
Array.prototype.filter = 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)
    }
  }
}

map 需要返回一个新数组,所以我们需要定义一个新数组。同时,我们还需要定义一个变量 resLen。

js 复制代码
let result = []
let resLen = 0

return result

filter 对于满足回掉的数组,才会返回,这里就需要在 for 循环中进行判断,是否符合,符合的情况下才会放入新数组中。

js 复制代码
if (i in O) {
  if (callback.call(thisArg, O[i], i, O)) {
     result[resLen++] = O[i]
  }
}

好的,五行代码,组合一下

js 复制代码
Array.prototype.filter = 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
  let result = []
  let resLen = 0
  for (let i = 0; i < len; i++) {
    if (i in O) {
      if (callback.call(thisArg, O[i], i, O)) {
        result[resLen++] = O[i]
      }
    }
  }
  return result
}

Array.prototype.reduce()

reduce 的使用

js 复制代码
const result = [1, 2, 3, 4, 5, 6].reduce((cur, pre) => {
  return cur + pre
}, 100)

框架抄下来,改个名字,这里有一个改动,我们需要传入 initValue

js 复制代码
Array.prototype.reduce = function (callback, initValue) {
  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)
    }
  }
}

默认返回初始值,因此 result === initValue

js 复制代码
let result = initValue

return result

当不提供初始值的时候,就取数组的第一个

js 复制代码
let i = 0;
if (initValue === undefined) {
  for (; i < len; i++) {
    if (i in O) {
      result = O[i];
      i++;
      break;
    }
  }
}

之后,按照正常的 for 循环,对 result 数组进行赋值

js 复制代码
for (; i < len; i++) {
  if (i in O) {
    result = callback.call(undefined, result, O[i], i, O);
  }
}

好的,对代码进行组装

js 复制代码
Array.prototype.reduce = function (callback, initValue) {
  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
}

下面两个,前面的 forEach 框架就不能用了

Array.prototype.push()

push 是返回新数组的长度,所以我们需要定义一个 newLength 用来作为新数组的长度。新数组的长度,当然是等于原来的长度+新传入的数据的长度。还需要做一些判断,比如,有一个非常非常非常非常长的数组,已经大于 2 ** 53 - 1。这个时候,就需要报错了。

js 复制代码
Array.prototype.push = function (...items) {
  const O = Object(this)
  const len = O.length >>> 0
  const argCount = items.length >>> 0
  if (len + argCount > 2 ** 53 - 1) {
    throw new Error("error")
  }
  let newLength = len + argCount
  O.length = newLength
  return newLength
}

当然,这只是长度的处理,还需要把新数据放入原数组中。

js 复制代码
for (let i = 0; i < argCount; i++) {
  O[len + i] = items[i]
}

组合一下

js 复制代码
Array.prototype.push = function (...items) {
  const O = Object(this)
  const len = O.length >>> 0
  const argCount = items.length >>> 0
  if (len + argCount > 2 ** 53 - 1) {
    throw new Error("error")
  }
  let newLength = len + argCount
  O.length = newLength
  for (let i = 0; i < argCount; i++) {
    O[len + i] = items[i]
  }
  return newLength
}

Array.prototype.pop()

pop 会删除数组的最后一项,并且返回删除的该项。如果长度为空,则会返回 undefined。

js 复制代码
Array.prototype.pop = function () {
  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
}

自此,我们的手写就完成了。

相关推荐
心平愈三千疾11 分钟前
通俗理解JVM细节-面试篇
java·jvm·数据库·面试
漂流瓶jz42 分钟前
清除浮动/避开margin折叠:前端CSS中BFC的特点与限制
前端·css·面试
清幽竹客1 小时前
vue-30(理解 Nuxt.js 目录结构)
前端·javascript·vue.js
weiweiweb8881 小时前
cesium加载Draco几何压缩数据
前端·javascript·vue.js
我不吃饼干9 天前
鸽了六年的某大厂面试题:你会手写一个模板引擎吗?
前端·javascript·面试
我不吃饼干9 天前
鸽了六年的某大厂面试题:手写 Vue 模板编译(解析篇)
前端·javascript·面试
LyaJpunov9 天前
深入理解 C++ volatile 与 atomic:五大用法解析 + 六大高频考点
c++·面试·volatile·atomic
前端fighter9 天前
为什么需要dependencies 与 devDependencies
前端·javascript·面试
满楼、9 天前
el-cascader 设置可以手动输入也可以下拉选择
javascript·vue.js·elementui
前端fighter9 天前
Vuex 与 Pinia:全面解析现代 Vue 状态管理的进化之路
前端·vue.js·面试