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

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

虽然已经不是挑战了,但还是要写,接下来是自己的挑战

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

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

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

昨天我们看了数组 map(), filter()手写实现 今天试试 reduce()

23. Array.prototype.reduce()

是什么

reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值

例子

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15
// 5 作为参数是初始值
复制代码

reducer 函数接收4个参数:

  • Accumulator (acc) (累计器)
  • Current Value (cur) (当前值)
  • Current Index (idx) (当前索引)
  • Source Array (src) (源数组)

您的 reducer 函数的返回值分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。

语法

arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
复制代码

参数

  • callback
    • 执行数组中每个值 (如果没有提供 initialValue 则第一个值除外)的函数,包含四个参数:
      • accumulator: 累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
      • currentValue 数组中正在处理的元素。
      • index 可选: 数组中正在处理的当前元素的索引。如果提供了initialValue,则起始索引号为 0,否则从索引 1 起始。
      • array 可选: 调用reduce()的数组
  • initialValue可选
    • 作为第一次调用 callback 函数时的第一个参数的值(初始值)。 如果没有提供初始值,则将使用数组中的第一个元素。
    • 在没有初始值的空数组上调用 reduce 将报错。

返回值
函数累计处理的结果。

关于 reduce 的更多用法建议参考 MDN

reduce 的英文含义是 减少,减轻,节减;缩短,缩小;降低 ,可以想象成一个数组,经过 reduce “缩减”成一个值

或者说,对这个数组迭代地进行处理,最后返回一个汇总结果。

手写实现

我们实现前再总结下重点:

reduce为数组中的每一个元素依次执行callback函数,(不包括数组中被删除或从未被赋值的元素),接受四个参数:

  • accumulator 累计器
  • currentValue 当前值
  • currentIndex 当前索引
  • array 数组

回调函数第一次执行时,accumulatorcurrentValue 的取值有两种情况:

  1. 如果提供了 initialValue:
  • accumulator 取值为 initialValue
  • currentValue 取数组中的第一个值
  1. 如果没有提供 initialValue,那么:
  • accumulator取数组中的第一个值
  • currentValue取数组中的第二个值
  • 在没有初始值的空数组上调用 reduce 将报错。

在看实现代码之前,建议先看上篇 map实现 , 很多思想都是相同的

Array.prototype.myReduce = function(callback, initialValue) {

  if (this == null) {
    throw new TypeError("Cannot read property 'reduce' of null or undefined");
  }
  if (typeof callback !== 'function') {
    throw new TypeError(callback + ' is not a function')
  }

  let O = Object(this)

  // 最后返回结果是最后的累计 accumulator
  let accumulator

  let k = 0
  
  // 初始值条件判断
  if (initialValue) {
    // 提供初值,accumulator 取值为 initialValue
    accumulator = initialValue
  } else {

    // 在没有初始值的空数组上调用 reduce 将报错。
    if (O.length === 0) {
      throw new TypeError('Reduce of empty array with no initial value');
    }

    // 如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true
    // 循环判断当 O 及其原型链上存在属性 k 时开始
    while (k < O.length && !(k in O)) {
      k++;
    }

    // 没有提供初值, `accumulator`取数组中的**第一个值**
    accumulator = O[k++]
  }

  while (k < O.length) {
    if (k in O) {
      let currentValue = O[k]
      accumulator = callback(accumulator, currentValue, k, O)
    }
    k++
  }

  return accumulator
}

const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

const array2 = [{label: '十', num: 10}, {label: '八', num: 8}];
const reducer2 = (acc, cur) => {
  return {
    label: `${acc.label} ${cur.label}`,
    num: acc.num + cur.num
  }
}

// 1 + 2 + 3 + 4
console.log(array1.myReduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.myReduce(reducer, 5));
// expected output: 15

console.log(array2.myReduce(reducer2, {label: '一', num: 0}));
复制代码

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

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

参考

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享