js Array.prototype.reduce API的理解

前言

看到一道有意思的题目:

// 假设本地机器无法做加减乘除运算,需要通过远程请求让服务端来实现。
// 以加法为例,现有远程API的模拟实现

const addRemote = async (a, b) => new Promise(resolve => {
  setTimeout(() => resolve(a + b), 1000)
});

// 请实现本地的add方法,调用addRemote,能最优的实现输入数字的加法。
async function add(...inputs) {
  // 你的实现
}

// 请用示例验证运行结果:
add(1, 2)
  .then(result => {
    console.log(result); // 3
});


add(3, 5, 2)
  .then(result => {
    console.log(result); // 10
})

题目不难,简单答案如下:

async function add(...args) {
  let res = 0;
  if (args.length <= 2) return res;

  for (const item of args) {
    res = await addRemote(res, item);
  }
  return res;
}

递归版本:

async function add(...args) {
  let res = 0;
  if (args.length === 0) return res;
  if (args.length === 1) return args[0];
  
  const a = args.pop();
  const b = args.pop();
  args.push(await addRemote(a, b));
  return add(...args);
}

本文主角版本:

async function add(...args) {
  return args.reduce((promiseChain, item) => {
    return promiseChain.then(res => {
      return addRemote(res, item);
    });
  }, Promise.resolve(0));
}

可以看出,最后一个版本的亮点如下:

  1. Promise链式调用
  2. reduce的掌握
  3. async function本质理解

本文只探讨其中的第二点,reduce的掌握

API介绍

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

参数

1. callback

一个回调函数,一下称这个函数为reducer。
reducer接收四个参数:

  1. accumulator 累加值
  2. currentValue 当前正在处理的值,可以理解为遍历(循环)中的item,当前项
  3. index 当前元素的索引,就是参数2的索引 (可选)
  4. array 调用reduce的数组 (可选)

2. initialValue (可选)

累加值的初始值,默认为数组的第一项。
这里有一个值得注意的地方:

注意:如果没有提供initialValue,reduce 会从索引1的地方开始执行 callback 方法,跳过第一个索引。如果提供initialValue,从索引0开始。

在我看来,reduce是一个内部封装好的遍历,是另一种形式的forEach,举个例子:

[1,2,3,4,5].reduce((a,b)=>a+b)

上述代码时一个基础的reduce例子,实现一个简单的累加器,执行结果为:1+2+3+4+5 = 15
上述代码因为没有指定InitialValue,所以会执行四次,初次的accumulator为1,currentValue为2;
等同于:

var accumulator = 0;
var demo = [1,2,3,4,5]
demo.forEach((item)=>{
	accumulator += item
})
console.log(accumulator); // 15

题目及其答案出处:今天聊:大厂如何用一道编程题考察候选人水平
个人学习记录,参考自: Reduce API

上一篇:【转载】Hive面试题


下一篇:reduce的使用 (完整版)