reduce() 方法将数组中的元素缩减为一个值,返回的这个值可以是任何类型。

reduce() 就像数组方法瑞士军刀。像 map()filter()之类的方法有特定的功能,而 reduce() 可以将输入数组转换为所需的任何输出,同时保留原始数组。

语法

const newValue = arr.reduce(function(accumulator, currentValue, index, array) {
  // Do stuff with accumulator and currentValue (index, array, and initialValue are optional)
}, initialValue);
  • newValue - 返回的新的数字、数组、字符串或对象
  • arr - 对其执行操作的数组
  • accumulator - 上一个遍历返回的值
  • currentValue - 数组中的当前元素
  • index - 当前元素的索引
  • array - 调用 reduce() 的原始数组
  • initialValue - 传递给函数的初始值,可以是一个数字、数组、字符串或对象

示例

ES5

var numbers = [1, 2, 3]; 

var sum = numbers.reduce(function(total, current) {
  return total + current;
}, 0);

console.log(numbers); // [1, 2, 3]
console.log(sum); // 6

ES6

const numbers = [1, 2, 3];

const sum = numbers.reduce((total, current) => {
  return total + current;
}, 0);

const sumOneLiner = numbers.reduce((total, current) => total + current, 0);

console.log(numbers); // [1, 2, 3]
console.log(sum); // 6
console.log(sumOneLiner); // 6

关于 initialValue

含有 initialValue

initialValue 参数是可选的。如果有,它是作为回调函数第一次调用后的初始值(计算结束后的返回值 total):

const numbers = [2, 3, 4];
const product = numbers.reduce((total, current) => {
  return total * current;
}, 1);

console.log(product); // 24

因为有 initialValue 为 1,reduce() 从数组的开头开始,将第一个元素(2)设置为当前元素(current)。然后遍历数组的剩余部分,同时更新累计值和当前元素。

没有 initialValue

如果没有 initialValue,遍历将从数组的第二个元素(索引为 1)开始,accumulator 等于数组的第一个元素,而 currentValue 等于数组的第二个元素:

const numbers = [2, 3, 4];
const product = numbers.reduce((total, current) => {
  return total * current;
});

console.log(product);

在这个例子中,没有 initialValue,所以 reduce() 将数组的第一个元素设置为累计值(total 等于 2),将数组的第二个元素设置为当前元素(currentValue 等于 3)。然后遍历数组的其余部分。

当缩减一个字符串数组时:

const strings = ['one', 'two', 'three'];
const numberString = strings.reduce((acc, curr) => {
  return acc + ', ' + curr;
});

console.log(numberString); // "one, two, three"

如果 reduce() 方法将返回一个数字或一个简单的字符串,那么很容易省略 initialValue 参数。如果是返回一个数组或对象,那么应该含有 initialValue 参数。

返回一个对象

将字符串数组转换为一个对象很简单,该对象可以显示每个字符串在数组中出现的次数。只需传递一个空对象({})作为 initialValue

const pets = ["dog", "chicken", "cat", "dog", "chicken", "chicken", "rabbit"];

const petCounts = pets.reduce(function(obj, pet) {
  if (!obj[pet]) {
    // if the pet doesn't yet exist as a property of the accumulator object,
    //   add it as a property and set its count to 1
    obj[pet] = 1;
  } else {
    // pet exists, so increment its count
    obj[pet]++;
  }
  
  return obj; // return the modified object to be used as accumulator in the next iteration
}, {}); // initialize the accumulator as an empty object

console.log(petCounts);
/*
{
  dog: 2, 
  chicken: 3, 
  cat: 1, 
  rabbit: 1 
}
*/

返回一个数组

通常,如果你要返回一个数组,那么 map() 是一个更好的选择。它告诉编译器(和其他阅读你的代码的人)原始数组中的每个元素都将被转换,并以等长的新数组形式返回。

另一方面,reduce() 表示原始数组的所有元素都将被转换为新值。该新值可以是一个数组,其长度可能与原始数组不同。

假设你有一个购物清单,其中包含字符串,但你想从清单中删除所有不喜欢的食物,那么你可以使用 filter() 过滤掉所有不喜欢的内容,并使用 map() 返回新的字符串数组,也可以只使用 reduce()

const shoppingList = ['apples', 'mangoes', 'onions', 'cereal', 'carrots', 'eggplants'];
const foodsIDontLike = ['onions', 'eggplants'];
const newShoppingList = shoppingList.reduce((arr, curr) => {
  if (!foodsIDontLike.includes(curr)) {
    arr.push(curr);
  }
  
  return arr;
}, []);

console.log(newShoppingList); // ["apples", "mangoes", "cereal", "carrots"]

以上就是有关 reduce() 方法的全部知识。它就像瑞士军刀一样,并不总是工作的最佳工具,但是当你真正需要它时,你会很高兴背后的口袋中有它。

原文:The Ultimate Guide to JavaScript Array Methods - Reduce