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

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

但是!!!!

八股文,该背还得背

那么

对于面试中的遇到的,手写数组的方法,比如 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
}

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

相关推荐
真的很上进4 小时前
如何借助 Babel+TS+ESLint 构建现代 JS 工程环境?
java·前端·javascript·css·react.js·vue·html
测试老哥4 小时前
外包干了两年,技术退步明显。。。。
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
ThisIsClark6 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
噢,我明白了7 小时前
同源策略:为什么XMLHttpRequest不能跨域请求资源?
javascript·跨域
sanguine__7 小时前
APIs-day2
javascript·css·css3
关你西红柿子7 小时前
小程序app封装公用顶部筛选区uv-drop-down
前端·javascript·vue.js·小程序·uv
测试19988 小时前
外包干了2年,技术退步明显....
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
济南小草根8 小时前
把一个Vue项目的页面打包后再另一个项目中使用
前端·javascript·vue.js
小木_.8 小时前
【python 逆向分析某有道翻译】分析有道翻译公开的密文内容,webpack类型,全程扣代码,最后实现接口调用翻译,仅供学习参考
javascript·python·学习·webpack·分享·逆向分析
Aphasia3118 小时前
一次搞懂 JS 对象转换,从此告别类型错误!
javascript·面试