数组的reduce()方法(Array.prototype.reduce())

457 阅读6分钟

reduce()方法将一个累加器和一个阵列元素从左至右依次传入一个回调函数,并最终返回一个值.

最终返回的值由回调函数的规则来决定.

一\语法

arr.reduce(callback[accumulator, currentValue, currentIndex, array], initialValue)

注释说明:

  • callback: 用于处理阵列中每个元素的函数,可以传入四个参数

    • accumulator:累加器.用来累积回调函数的累加器,对于累加器的初始值,如果有设定,即设定有初值,那么这个累加器在第一次执行回调函数时就是这个初始值 (initialValue),如果没有设定初始值,那么第一次执行回调函数时,累加器就等于陈列元素的第0项值.之后每次调用回调函数时,累加器的值就等于上次执行函数的结果.
    • currentvalue:当前值.当前值是指每次执行回调函数时从左到右的依次值.如果设定了累加器的初始值,那么执行回调函数时就从陈列元素的第0项开始做为当前值,依次向右;如果没有设定初始值 ,那么陈列元素的第0项将作为累加器的值,第一项则成了第一次回调时的当前值..
    • currentIndex:当前索引.原陣列当前所迭代處理中的元素之索引。若有傳入 initialValue,則由索引 0 之元素開始,若無則自索引 1 之元素開始。为可选参数
    • array:数组.呼叫 reduce() 方法的陣列,是个可选参数,可以不指定,即默认为arr.

    所以,本方法实际必需要传入的参数仅有两个,即accumulator(累加器)和当前值(currentValue).所以本方法的最简化语法就是:

    arr.reduce(callback[accumulator,currentValue])
    

    二\请注意

  1. 如果陈列元素为空,且没有提供初始值(initalValue),该方法将为抛出类型错误(TypeError)
  2. 如果陈列元素只有一个值 ,且没有提供初始值,或虽然提供了初始值但阵列为空,那就将这个唯一的值回传而不调用回调函数

三\reduce()的工作方法

1\将阵列中的所有元素值相加

例1:无初始值的累加

let arr = [1,2,3,4];
let arr2 = arr.reduce((a,b)=>a+b);
console.log(arr2);
//10

//当然上方代码中的箭头函数也可以写function函数,其执行结果一样.即:
let arr2 = arr.reduce(function(a,b){
    return a+b;
});
//以上示例是没有指定初始值的情况,其执行过程如下表所示:


callback accumulator currentValue currentIndex arr return value
第一次 1 2 1 [1,2,3,4] 3
第二次 3 3 2 [1,2,3,4] 6
第三次 6 4 3 [1,2,3,4] 10

例2:有初始值 的累加

let arr = [1,2,3,4];
let arr2 = arr.reduce((a,b)=>{return a+b},10);
console.log(arr2);
//20

//或者写成:
let arr2 = arr.reduce(function(a,b){
    return a+b;
},10);
//本例代码是指定的初始值的情况,其执行过程如下:
callback accumulator currentValue currentIndex arr return Value
第一次 10 1 0 [1,2,3,4] 11
第二次 11 2 1 [1,2,3,4] 13
第三次 13 3 2 [1,2,3,4] 16
第四次 16 4 3 [1,2,3,4] 20

2\摊平一个多维阵列

可以借助数组的concat()方法,使用reduce()方法将一个多维数组摊平.

例:

let arr = [[1,2],[3,4],[5,6],[7,8]];
let arr2 = arr.reduce(function(a,b){
return a.concat(b);
},[]);
console.log(arr2)  //[1,2,3,4,5,6,7,8]

//或者使用箭头函数,写成:

let arr2 = arr.reduce((a,b)=>a.concat(b));
console.log(arr2)  //[1,2,3,4,5,6,7,8] 执行结果一样

3/计算相同元素数量并以键值对表示

可以使用reduce()方法来遍历一个数组,并找出数组中的相同项,例:

let names = ["Alice","张加成","李大营","Bob","John","张加成"];
let countedNames = names.reduce(function(allNames,name){
    if(name in allNames){
        allNames[name]++;
    }else{
        allNames[name] = 1;
    }
    return allNames;
},{});
console.log(countedNames); 
//{Alice: 1, 张加成: 2, 李大营: 1, Bob: 1, John: 1};
//在本例中,先初始化一个空对像作为累加器,然后使用reduce()方法遍历数组names,将数组中的每个一名字与累加器对像中的名字做对比,如果原累加器中没有遍历到的名字,则将该名字写入累加器,并将其值设置为1;如果累加器中已经存在该名字,那么它的值就自动加1;其执行过程如下:

callback accumulator currentValue currentIndex return value
第一次 {} "Alice" 0 {Alice:1}
第二次 {Alice:1} "张加成" 1 {Alice:1,张加成:1}
第三次 {Alice:1,张加成:1} "李大营" 2 {Alice:1,张加成:1,李大营:1}
第四次 {Alice:1,张加成:1,李大营:1} "Bob" 3 {Alice:1,张加成:1,李大营:1,Bob:1}
第五次 {Alice:1,张加成:1,李大营:1,Bob:1} "John" 4 {Alice:1,张加成:1,李大营:1,Bob:1,John:1}
第六次 {Alice:1,张加成:1,李大营:1,Bob:1,John:1} "张加成" 5 {Alice:1,张加成:2,李大营:1,Bob:1,John:1}

最终返回值为:{Alice:1, 张加成:2, 李大营:1, Bob:1,John:1 }

4\使用展开运算符和给定的初始值,结合数组中的阵列元素

例:

let friends = [{
	name:"赵小亮",
	books:["《罗密欧与朱丽叶》""《简爱》""《奋斗》"],
	age:28
	},{
	name:"张二牛",
	books:["《HTML&CSS》""《javascript程序开发》""《JAVAscript权威指南》"],
	age:21
	},{
	name:"李新书",
	books:["《平凡的世界》""《和你在一起》""《天道》"],
	age:32
	},{
	name:"王五四",
	books:["《红高梁》""《平凡的世界》""《民俗通书》"],
	age:41
	}	
];
let allBooks = friends.reduce(function(prev,curr){
    return [...prev,...curr.books]
},["《王二小放牛》"])
console.log(allBooks);


// 在本例中,先将一个数组["《王二小放牛》"]作为初始值,然后,使用数组的reduce()方法对目标数组friends中的每一项进行遍历,并使用展开运算符“...”将初始值和遍历后所得到的books的值(也是个数组)展开后重新放入初始数组中返回出来。

5、结合排序的方法将数组中重复的序号去除

例:
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4,];
let result = arr.sort().reduce((init,current)=>{
    if(init.length === 0 || init[init.lenght-1]!==current){
        init.push(current);
    }
    return init;
},[])
console.log(result);
//[1, 2, 3, 4, 5]

//本例中,先对原数组进行从小到大的排序,然后使用reduce()方法对排序后的数组进行遍历,先初始化一个累加器为一个空数组。然后在遍历的过程中,判断累加器数组的长度,如果数组长度为0,即空数组,或者,数组中第(数组长度减1)的位置的值不等于当前值,那就当前值添加到数组中(反之就不添加)。这样就把排序后的数组中重复的数字给筛选了来了。

6、序列执行promise

例:
function runPromiseInSequense(arr) {
  return arr.reduce((promiseChain, currentPromise) => {
    return promiseChain.then((chainedResult) => {
      return currentPromise(chainedResult)
        .then((res) => res)
    })
  }, Promise.resolve());
}

// promise function 1
function p1() {
  return new Promise((resolve, reject) => {
    resolve(5);
  });
}

// promise function 2
function p2(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 2);
  });
}

// promise function 3
function p3(a) {
  return new Promise((resolve, reject) => {
    resolve(a * 3);
  });
}

const promiseArr = [p1, p2, p3];
runPromiseInSequense(promiseArr)
  .then((res) => {
    console.log(res);   // 30
  });