前端必刷手写题系列 [12]

262 阅读7分钟

这是我参与更文挑战的第 29 天,活动详情查看 更文挑战

这个系列也没啥花头,就是来整平时面试的一些手写函数,考这些简单实现的好处是能看出基本编码水平,且占用时间不长,更全面地看出你的代码实力如何。一般不会出有很多边界条件的问题,那样面试时间不够用,考察不全面。

平时被考到的 api 如果不知道或不清楚,直接问面试官就行, api 怎么用这些 Google 下谁都能马上了解的知识也看不出水平。关键是在实现过程,和你的编码状态习惯思路清晰程度等。

注意是简单实现,不是完整实现,重要的是概念清晰实现思路清晰,建议先解释清除概念 => 写用例 => 写伪代码 => 再实现具体功能,再优化,一步步来。

21. Array.prototype.map()

是什么

map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值

测试用例

let arr = [1, 2, 3]
let test1 = arr.map(item => item * 2)
let test2 = arr.map((it, index) => {
    return {
        idx: index,
        value: it
    }
})

console.log(test1)
// [ 2, 4, 6 ]
console.log(test2) 
// [ { idx: 0, value: 1 }, { idx: 1, value: 2 }, { idx: 2, value: 3 } ]
console.log(arr) 
// [ 1, 2, 3 ] 原数组不变

语法

var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])

参数

  • callback
    • 生成新数组元素的函数,使用三个参数:
      • currentValue: callback 数组中正在处理的当前元素。
      • index 可选: callback 数组中正在处理的当前元素的索引。
      • array 可选: map 方法调用的数组。
  • thisArg可选
    • 执行 callback 函数时值被用作this。

返回值 一个由原数组每个元素执行回调函数的结果组成的新数组。

描述

  • map 方法会给原数组中的每个元素都按顺序调用一次 callback 函数。callback 每次执行后的返回值(包括 undefined)组合起来形成一个新数组。 callback 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。

  • 因为map生成一个新数组,当你不打算使用返回的新数组却使用map是违背设计初衷的,请用forEach或者for-of替代。这两种情况你不该使用map:

    • 你不打算使用返回的新数组
    • 你没有从回调函数中返回值。
  • callback 函数会被自动传入三个参数:数组元素,元素索引,原数组本身

  • 如果 thisArg 参数提供给map,则会被用作回调函数的this值。否则undefined会被用作回调函数的this值。

  • map 不修改调用它的原数组本身(当然可以在 callback 执行时改变原数组)

  • map 方法处理数组元素的范围是在 callback 方法第一次调用之前就已经确定了。调用map方法之后追加的数组元素不会被callback访问。如果存在的数组元素改变了,那么传给callback的值是map访问该元素时的值。在map函数调用后但在访问该元素前,该元素被删除的话,则无法被访问到。

  • 根据规范中定义的算法,如果被map调用的数组是离散的,新数组将也是离散的保持相同的索引为空。

简单手写实现

我们实现前总结下重点:

  1. map 方法主要就是给原数组中的每个元素都按顺序调用一次 callback 函数。并且把所有返回的结果组合在一起生成一个新的数组返回。

  2. 两个参数,必填项回调函数 callback 和 可选项 thisArg (callbackfn 函数执行时的 this 值)

测试用例就用上面的就行

Array.prototype.myMap = function(callbackfn, thisArg) {
  // 平时后端一个数组一不小心返回了 null,你又没做好[]兜底,控制台的报错
  if (this == null) {
    throw new TypeError("Cannot read property 'map' of null or undefined");
  }
  // callbackfn 不是函数时抛出异常
  if (typeof callbackfn !== 'function') {
    throw new TypeError(callbackfn + ' is not a function')
  }

  // this 转成数组对象,有迭代器
  let O = Object(this)

  // 不影响原数组,新建一个数组
  let newArr = new Array(O.length)

  for (let k = 0; k < O.length; k++) {
    // 检查 O 及其原型链是否包含属性 k
    if (k in O) {
      let currentValue = O[k]
      // 传入 thisArg, 当前元素 currentValue, 索引 index(k), 原数组对象 array(O)
      let mappedValue = callbackfn.call(thisArg, currentValue, k, O)
      // 返回结果赋值给新数组
      newArr[k] = mappedValue
    }
  }
  return newArr
}

let arr = [1, 2, 3]
let test1 = arr.myMap(item => item * 2)
let test2 = arr.myMap((it, index) => {
    return {
        idx: index,
        value: it
    }
})

console.log(test1)
// [ 2, 4, 6 ]
console.log(test2) 
// [ { idx: 0, value: 1 }, { idx: 1, value: 2 }, { idx: 2, value: 3 } ]
console.log(arr) 
// [ 1, 2, 3 ]

22. Array.prototype.filter()

是什么

filter() 方法创建一个新数组, 其包含通过提供函数实现测试所有元素。 主要作用其实就是过滤。

// let arr = [1, 2, 3, 4, 5, 6]
// let test1 = arr.filter(item => item > 3)

// console.log(test1)
// // [ 4, 5, 6 ]
// console.log(arr) 
// // [ 1, 2, 3, 4, 5, 6 ]

语法

var newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

参数

  • callback
    • 用来测试数组的每个元素的函数。返回 true 表示该元素通过测试,保留该元素,false 则不保留。它接受以下三个参数:
      • element: 数组中当前正在处理的元素。
      • index 可选: 正在处理的元素在数组中的索引。
      • array 可选: 调用了 filter 的数组本身。
  • thisArg可选
    • 执行 callback 时,用于 this 的值。

返回值 一个新的、由通过测试的元素组成的数组,如果没有任何数组元素通过测试,则返回空数组。

描述

  • filter 为数组中的每个元素调用一次 callback 函数,并利用所有使得 callback 返回 true 或等价于 true 的值的元素创建一个新数组

  • callback 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callback 测试的元素会被跳过,不会被包含在新数组中

  • callback 被调用时传入三个参数:

    • 元素的值
    • 元素的索引
    • 被遍历的数组本身
  • 如果为 filter 提供一个 thisArg 参数,则它会被作为 callback 被调用时的 this 值

  • filter 不会改变原数组,它返回过滤后的新数组

  • filter 遍历的元素范围在第一次调用 callback 之前就已经确定了。在调用 filter 之后被添加到数组中的元素不会被 filter 遍历到。如果已经存在的元素被改变了,则他们传入 callback 的值是 filter 遍历到它们那一刻的值。被删除或从来未被赋值的元素不会被遍历到。

简单手写实现

实现前总结下重点:

  1. filter 方法主要作用就是过滤,他需要设置一个测试函数callback,用来过滤数组中元素。留下所有测试函数返回 true 或等价于 true的元素。

  2. 两个参数,必填项用来测试数组的每个元素的函数 callback 和 可选项 thisArg (callback 函数执行时的 this 值)

实现倒不难,和 map 类似,看代码

Array.prototype.myFilter = function(callback, thisArg) {
  // 上题有说明这里就略过
  if (this == null) {
    throw new TypeError("Cannot read property 'filter' of null or undefined");
  }
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function')
  }

  let O = Object(this)

  let newArr = new Array(O.length)

  let to = 0

  for (let k = 0; k < O.length; k++) {
    if (k in O) {
      let element = O[k]
      // 就这边是不同,callback是个判断函数
      if (callback.call(thisArg, element, k, O)) {
        newArr[to++] = element;
      }
    }
  }
  newArr.length = to;
  
  return newArr
}

let arr = [1, 2, 3, 4, 5, 6]
let test1 = arr.myFilter(item => item > 3)

console.log(test1)
// [ 4, 5, 6 ]
console.log(arr) 
// [ 1, 2, 3, 4, 5, 6 ]

另外向大家着重推荐下另一个系列的文章,非常深入浅出,对前端进阶的同学非常有作用,墙裂推荐!!!核心概念和算法拆解系列 记得点赞哈

今天就到这儿,想跟我一起刷题的小伙伴可以加我微信哦 点击此处交个朋友 Or 搜索我的微信号infinity_9368,可以聊天说地 加我暗号 "天王盖地虎" 下一句的英文,验证消息请发给我 presious tower shock the rever monster,我看到就通过,加了之后我会尽我所能帮你,但是注意提问方式,建议先看这篇文章:提问的智慧

参考