JavaScript的reduce如何工作

JavaScript的reduce如何工作

一个简单的问题,你如何来求一个数组的和。

1
2
3
const arr = [29,27,2,23];
const sum = arr.reduce((total,amount)=>total+amount);
console.log(sum); //81
  • 在这个例子中,reduce接受两个参数,total参数和amount参数。
  • reduce函数循环遍历数组,像for循环一样。
  • 当循环开始时,total参数是最左边的29,amount参数值是27.
  • 函数会把total的值加上amount的值,然后赋值给total。
  • 然后下次函数total的值为56,amount的值为2,一直向右循环,直到没有数据时函数会把total的值返回。

计算数组的平均值。

reduce方法中的函数其余的参数,剩余第一个参数的含义为,数据在数组中的下标(从零开始),最后一个为数组本身。

1
2
3
4
5
6
7
8
9
10
11
12
const arr = [29,27,2,23];
const average = arr.reduce((total,amount,index,array)=>{
total+=amount;
if(index===array.length-1){
return total/array.length;
}else{
return total;
}
});
console.log(average);//20.25
```

如何用reduce方法返回一个数组。

上面的例子都是返回一个数值,你也可以返回一个数组,这就需要用到reduce函数的第二个参数。指定reduce方法第一个参数函数的第一个参数。在以前的例子中,我们忽略了它。默认为数组的第一个数据。

1
2
3
4
5
6
7
8
9
const arr = [29,27,2,23];
const average = arr.reduce((total,amount)=>{ //total为29,amount为27
total+=amount;
if(index===array.length-1){
return total/array.length;
}else{
return total;
}
});

但如果我们给reduce函数加上了第二个参数如:10,代码如下:这时total为10,amount变成了数组的第一个数据29

1
2
3
4
5
6
7
8
9
const arr = [29,27,2,23];
const average = arr.reduce((total,amount,index,array)=>{ //total为29,amount为27
total+=amount;
if(index===array.length-1){
return total/array.length;
}else{
return total;
}
},10); //此时平均值的结果的计算要数组元素加上10,在求平均值22.75

有了上面的知识,我们可以把reduce的第二个参数设置为数组,作为参数传入。就可以返回数组。代码如下(将数组数据乘二返回):

1
2
3
4
5
6
7
const arr = [2,3,4,5];
const doubled = arr.reduce((total,amount)=>{ //注意此时的total为[],amount为2
total.push(amount*2);
return total;
},[]);
console.log(doubled); //[4,6,8,10]

我们也可以在其中添加if判断,过滤掉我们不需要的数据

1
2
3
4
5
6
7
8
9
const arr = [2,3,4,5];
const doubled = arr.reduce((total,amount)=>{ //注意此时的total为[],amount为2
if(amount>3){
total.push(amount*2);
}
return total;
},[]);
console.log(doubled); //[8,10]

上面的方法是map和filter方法被reduce方法重写,或许没有map与filter方法更容易让人理解,但reduce方法的好处是你可以综合使用它们,并且操作大量的数据。

我们再来讨论一个问题,你有一个集合,想知道每一个元素在集合中的数目。

我们可以利用reduce来解决

1
2
3
4
5
6
const basket = ['banana','cherry','apple','banana','cherry','apple','orange'];
const count = basket.reduce((total,fruit)=>{
total[fruit] = (total[fruit]||0)+1;
return total;
},{});
console.log(count); //{banana: 2, cherry: 2, apple: 2, orange: 1}

使用reduce方法也可以将嵌套数组扁(数组里面嵌套数组)平化为一个数组(与嵌套数组意思相反)

1
2
3
4
5
const data = [[2,3,4,5],[6,7,8,9],[11,22,33,44]];
const flat = data.reduce((total,amount)=>{
return total.concat(amount);
},[]);
console.log(flat);

有时候数据嵌套太深,我们该如何处理,获得data数组中每个对象的中的颜色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const data = [{
a: 'happy',
b: 'robin',
c: ['blue','green']
},
{
a: 'tired',
b: 'panther',
c: ['blue','green','black','blue']
},
{
a: 'sad',
b: 'gold',
c: ['blue','red']
},
];
const colors = data.reduce((total,amount)=>{
amount.c.forEach(color=>{
total.push(color);
});
return total;
},[]);

那我们如何获取颜色种类呢(去掉重复的颜色,只保留一个)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = [{
a: 'happy',
b: 'robin',
c: ['blue','green']
},
{
a: 'tired',
b: 'panther',
c: ['blue','green','black','blue']
},
{
a: 'sad',
b: 'gold',
c: ['blue','red']
},
];
const colors = data.reduce((total,amount)=>{
amount.c.forEach(color=>{
if(total.indexOf(amount)===-1){
total.push(color);
}
});
return total;
},[]);

reduce的另一个强大之处是他可以处理函数

假设我们有一个函数集合,这些函数可以允许我们增加,减少,相乘,折半某一个数字

1
2
3
4
5
6
7
8
9
10
11
12
function increment(input){
return input+1;
}
function decrement(input){
return input-1;
}
function double(input){
return input*2;
}
function half(input){
return input/2;
}

在某种情况下,我们需要对某一个数进行增加,减少,相乘,折半。我们需要写一个函数,返回((input+1)*2-1)/2,我们可以利用reduce函数创造一个管道来解决。

管道是一系列函数把一个初始值转化为最终值的过程

代码如下:

1
2
3
4
5
var pipeline = [increment,double,decrement,half];
const result = pipeline.reduce((total,fun)=>{
return fun(total);
},2);
console.log(result);