JavaScript中reduce的5种使用方法

408 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

现代 JavaScript 为数组提供了许多方法。其中最受欢迎的是 forEach、for 或 for...of。如果您需要遍历数组并为每个元素返回数据,map 是合适的。

如果您需要遍历数组,例如汇总所有值、求平均值或执行任何中间操作,最好使用 reduce 方法。

在什么情况下可以使用它 - 在这篇文章中。

减少将数组折叠为一个值(减少)。该值可以是任何类型的数据——原始数据和复合数据,例如数组。

该方法接受两个参数:

  • 执行回调函数以运行数组中的每个元素;
  • 初始值的初始值。Callback 还接受两个参数:accumulator,它在访问另一个元素后返回回调函数,以及 currentValue 循环中的当前元素。

让我们考虑一下 reduce 方法的几个非显而易见的应用,它们将有助于坚持 write less, do more 原则。

数组中的最小值和最大值

要查找最小值和最大值,您可以使用 Math API,例如:

const array = [-11, 2, 21, 3];
const max = Math.max(...array); // 21
const min = Math.min(...array); // -11

但是当使用大数组(~10^7)时,你可能会遇到错误。您可以使用 reduce 方法消除这些问题并获得所需的结果。

const array = [-11, 2, 21, 3];
const max = array.reduce((max, num) => (max > num ? max : num)); // 21
const min = array.reduce((min, num) => (min < num ? min : num)); // -11

您可能需要解析 GET URL 中的参数并将它们添加到对象中。

const parseQuery = () => {
  const url = new URL("https://ranbow1.xyz?name=hello&title=world");
  const search = url.search;
  let query = {};
  search
    .slice(1)
    .split("&")
    .forEach((item) => {
      const [key, value] = item.split("=");
      query[key] = decodeURIComponent(value);
    });
  return query;
};
// {name: "hello", title: "world"}

但是使用 reduce 方法,一切都变得更加清晰和可预测:

const parseQuery = () => {
  const url = new URL("https://ra1nbow.xyz?name=hello&title=world");
  const search = url.search;
  return search
    .replace(/(^?)|(&$)/g, "")
    .split("&")
    .reduce((query, item) => {
      const [key, value] = item.split("=");
      query[key] = decodeURIComponent(value);
      return query;
    }, {});
};
// {name: "hello", title: "world"}

以下是它的工作原理:

  1. 从 URL 获取搜索参数?name=hello&title=world
const search = url.search;  // ?name=hello&title=world
  1. 删除不必要的字符
search.replace(/(^?)|(&$)/g, "");
//?name=hello&title=world => name=hello&title=world
  1. 我们使用reduce将参数收集到一个对象中

参数的反序列化

在这个例子中,情况正好相反。如果需要在链接中添加一组参数,使用拼接(粘合线)不是很方便,特别是如果有几十个或几百个这样的参数。正因为如此,代码的可读性显着下降,每增加一个新的参数,行数就会增加,这给进一步的支持带来了困难。

const searchObj = {
  name: 'hello',
  title: 'world',
}; // many others parameters
const link = `https://ra1nbow.xyz?name=${searchObj.name}&age=${searchObj.title}`;

您可以使用 reduce 方法纠正这种情况。首先,我们编写函数:

const stringifySearch = (search = {}) => {
  return Object.entries(search)
    .reduce(
      (t, v) =>     `${t}${v[0]}=${encodeURIComponent(v[1])}&`,
      Object.keys(search).length ? '?' : ''
    )
    .replace(/&$/, '');
};

接下来,我们从前面描述的示例中获取对象并应用它:

const searchObj = {
  name: 'hello',
  title: 'world',
}; // many others parameters
const search = stringifySearch(searchObj);
const link = `https://ra1nbow.xyz${search}`; // https://ra1nbow.xyz?name=hello&title=world

现在您不必担心当您更改对象时,后续代码将无法正常工作。

选择数组的唯一元素

很简单:我们遍历数组,寻找其中是否已经存在这样的含义。如果没有,我们添加它,如果有,我们更进一步。因此,输出将是一个只有唯一值的数组。

const someArray = [1, 2, 1, 2, -1, 10, 11];
const uniqueArray = someArray.reduce(
  (acc, item) => (acc.includes(item) ? acc : [...acc, item]),
  []
); // [1, 2, -1, 10, 11]

确定数组中相同元素的数量

为了获取数组中每个元素的数量,我们另外使用 Map - 这是一个键值的集合,以及 Object。

主要区别在于,在 Map 中,我们将能够使用使用不同类型(数字/行)值的数组。\

const count = (array) => {
  return array.reduce(
    (acc, item) => (acc.set(item, (acc.get(item) || 0) + 1), acc),
    new Map()
  );
};
const array = [1, 2, 1, 2, -1, 0, 0, 10, 10, 6];
console.log(count(array)); // Map(6) {1 => 2, 2 => 2, -1 => 1, 0 => 2, 10 => 2, 6 => 1}

获取多个对象属性

这样的场景在日常工作中经常发生。让我们看一个例子。

我们有一个具有许多属性的对象:

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  e: 5
  // ...
}

我们想要获取前一个对象的一些属性并创建一个新对象:

const newObj = {
  a: obj.a,
  b: obj.b,
  c: obj.c,
  d: obj.d
  // ...
}

它似乎不是很有效,是吗?

让我们写一个小助手,让我们更容易解决问题:

const getObjectKeys = (obj = {}, keys = []) => {
  return Object.keys(obj).reduce(
    (acc, key) => (keys.includes(key) && (acc[key] = obj[key]), acc),
    {}
  );
};

当然,让我们检查一下它是如何工作的:

const obj = {
  a: 1,
  b: 2,
  c: 3,
  d: 4,
  e: 5
  // ...
}
const newObj = getObjectKeys(obj, [ 'a', 'b', 'c', 'd' ])
console.log(newObj) // {a: 1, b: 2, c: 3, d: 4}

最后

这只是在日常任务中应用该方法的可能场景的一部分。我希望你自己找到一些有趣的东西。

感谢您的关注和愉快的编码!