Array.reduce功能有多强?学会这几个用法,代码减少50%!

120 阅读7分钟

array-reduce-javascript.jpg

Array.reduce()大家并不陌生,你真的会使用吗?下面给你大家介绍几个项目中常用示例,让你彻底理解Array.reduce()

一、数字求和 

reduce()最直接的用例之一就是对一堆数字求和。假设你有一个整数数组,你想找出它们的总和。

const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, curr) => acc + curr, 0);
console.log(sum); // Output: 15

仅用一行代码,就计算出了数组中所有元素的和。累加器的初始值设置为0,并且在每次迭代中,将当前元素添加到累加器中。

如果你选择省略起始值,reduce将只使用数组中的第一项。不过,我倾向于总是包含一个初始值,这样更容易阅读。

二、扁平化数组 

若果你有一个二维数组,希望它平铺成一个数组?

const array = [[1, 2], [3, 4], [5, 6]];
const flateArray = array.reduce((acc, curr) => acc.concat(curr), []);
console.log(flateArray); // Output: [1, 2, 3, 4, 5, 6]

在本例中,我们以一个空数组作为累加器的初始值。然后,在每次迭代中,我们使用concat()方法将当前子数组连接到累加器。最后,我们得到了一个完美的扁平数组。

我知道你也可以用Array.flat()做到这一点。然而,了解如何使用reduce是很重要的,而且reduce可以对每个项执行额外的操作。

三、对象分组 

假设后端返回一个对象数组,并且希望根据特定属性对它们进行分组。Reduce()是完成这项工作的完美工具。

const people = [
  { name: '张三', age: 25 },
  { name: '李四', age: 30 },
  { name: '王五', age: 25 },
  { name: '赵六', age: 30 }
];

const groupedByAge = people.reduce((acc, curr) => {
  if (!acc[curr.age]) {
    acc[curr.age] = [];
  }
  acc[curr.age].push(curr);
  return acc;
}, {});

console.log(groupedByAge);
/*
Output:
{
  '25': [{ name: '张三', age: 25 }, { name: '王五', age: 25 }],
  '30': [{ name: '李四', age: 30 }, { name: '赵六', age: 30 }]
}
*/

在本例中,我们使用一个对象作为初始累加器值。我们检查累加器是否已经有当前年龄的属性。如果没有,则为该年龄创建一个空数组。然后,将当前对象推入相应的age数组。最后,我们得到一个对象,其中键是年龄,值是具有该年龄的人的对象。

当然现在你也可以使用Object.groupBy()方法,但是,了解这个reduce方法的实现原理非常的重要。

四、创建查找映射 

我个人最喜欢的是使用reduce()从数组创建查找映射。当涉及到Js性能和代码可读性时,reduce必须首选,停止使用那些缓慢的find()或filter()循环调用。

const products: Product[] = [
  { id: 1, name: '华为', price: 2999 },
  { id: 2, name: '小米', price: 1999 },
  { id: 3, name: '苹果', price: 4999 },
];

const productMap = products.reduce((acc, curr) => {
  acc[curr.id] = curr;
  return acc;
}, {});

console.log(productMap);
/*
Output:
{
  '1': { id: 1, name: '华为', price: 2999 },
  '2': { id: 2, name: '小米', price: 1999 },
  '3': { id: 3, name: '苹果', price: 4999 }
}
*/

// 通过 Id 获得商品对象
const hauwei = productMap[1];
console.log(hauwei); // Output: { id: 1, name: '华为', price: 2999 }

‍通过使用reduce()来创建一个查找映射,您可以在恒定的时间复杂度下通过唯一Id标识符访问元素。不再循环遍历数组就可以查找特定项。

五、计算出现次数 

当你需要计算数组中元素的出现的次数,Reduce()非常适合。

const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];

const fruitCounts = fruits.reduce((acc, curr) => {
  acc[curr] = (acc[curr] || 0) + 1;
return acc;
}, {});

console.log(fruitCounts);
/*
Output:
{
  'apple': 3,
  'banana': 2,
  'orange': 1
}
*/

‍在本例中,我们将一个空对象初始化为累加器。对于数组中的每个水果,我们检查它是否已经作为属性存在于acc对象中。如果是,则将其计数增加1,否则我们将其初始化为0,返回结果是一个对象,它告诉我们每个水果在数组中出现了多少次。

六、组合函数 

函数式编程爱好者会非常喜欢这么使用。Reduce()是组合函数的强大工具。您可以使用它来创建一个逐步转换数据的函数管道。

const add5 = (item) => item + 5;
const multiply3 = (item) => item * 3;
const subtract2 = (item) => item - 2;
const composedFunctions = [add5, multiply3, subtract2];
const result = composedFunctions.reduce((acc, curr) => curr(acc), 10);
console.log(result); // Output: 43

‍在本例中,我们有一个函数数组,我们希望将其按顺序应用于初始值10。我们使用reduce()遍历函数,将每个函数的结果作为输入传递给下一个函数。最终结果是按组合顺序应用所有函数的结果。

七、数组去重 

有时,你可能有一个包含重复值的数组,你现在需要去除重复元素。Reduce()可以帮助您轻松地完成此任务。

const numbers: number[] = [1, 2, 3, 2, 4, 3, 5, 1, 6];

const uniqueNumbers: number[] = numbers.reduce((acc, curr) => {
  if (!acc.includes(curr)) {
    acc.push(curr);
  }
  return acc;
}, []);

console.log(uniqueNumbers); // Output: [1, 2, 3, 4, 5, 6]

‍这里,我们将一个空数组初始化为累加器。对于原始数组中的每个数字,我们使用includes()方法检查它是否已经存在于累加器中。如果没有,则将其加入累加器数组。

八、计算平均值 

想要计算一组数字的平均值吗?Reduce()支持你!

const numbers = [85, 90, 92, 88, 95];

const average = numbers.reduce((acc, curr, index, array) => {
  acc += curr;
  if (index === array.length - 1) {
    return acc / array.length;
  }
  return acc;
}, 0);

console.log(average); // Output: 90

‍在本例中,我们将累加器初始化为0。我们遍历每个元素并将其添加到累加器中。当我们到达最后一个元素(使用index和array.length检查)时,我们将累加器除以总等级数来计算平均值。

九、性能考虑事项 ️

虽然Array.reduce()非常强大和通用,但了解潜在的性能缺陷很重要,特别是在处理大型数组或复杂操作时。一个常见的陷阱是在reduce()的每次迭代中创建新对象或数组,这可能导致内存分配过多并影响性能。

例如,考虑下面的代码:

const numbers: number[] = [1, 2, 3, 4, 5];

const doubledNumbers = numbers.reduce((acc, curr) => {
  return [...acc, curr * 2];
}, []);

console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]

‍在本例中,我们使用扩展操作符(…)在每次迭代中创建一个新数组,这可能效率很低。相反,我们可以通过直接改变累加器数组来优化代码:

const numbers: number[] = [1, 2, 3, 4, 5];

const doubledNumbers: number[] = numbers.reduce((acc, curr) => {
  acc.push(curr * 2);
  return acc;
}, []);

console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]

‍通过使用push()改变累加器数组,我们避免在每次迭代中创建新数组,从而获得更好的性能。

类似地,当处理对象时,直接改变累加器对象比使用扩展操作符创建新对象更有效:

const people = [
  { name: '张三', age: 25 },
  { name: '李四', age: 30 },
  { name: '王五', age: 25 },
  { name: '赵六', age: 30 }
];

const groupedByAge = people.reduce((acc, curr) => {
  if (!acc[curr.age]) {
    acc[curr.age] = [];
  }
  acc[curr.age].push(curr);
  return acc;
}, {});

‍通过直接改变累加器对象,我们优化了reduce()操作的性能。

然而,在某些情况下,在每次迭代中必须创建新对象或数组,或者更具可读性。根据您的特定用例和正在处理的数据的大小,在性能和代码清晰度之间取得平衡是很重要的。

结论 

以上几个常用的示例展示了Array.reduce()的强大功能。从对数字求和到将数组扁平化,对象分组到创建查找映射,对出现次数进行统计到组合函数,甚至计算平均值,Array.reduce()证明是Js工具包中的一个强大工具。

你觉得呢?你最喜欢的数组方法是什么?

也可以添加我V: code7878领取前端教程或者技术交流。