1、语法
array.reduce(callback,[initiaValue]);
reduce 为数组中的每一个元素执行回调函数,不包括未被赋值的元素。
回调函数中有四个参数
2、回调函数参数
- previousValue : 上一次调用返回的值,因为第一次没有返回值,所以第一次默认返回1
- currentValue : 当前值,默认从数组下标为 1 的开始
- currentIndex : 当前索引,默认从数组下标为 1 的开始
- array : 当前数组
var arr = [1,2,3,4,5];
arr.reduce(function(previousValue,currentValue,currentIndex,array){
console.log(previousValue,currentValue,currentIndex,array);
//1 2 1 (5) [1, 2, 3, 4, 5]
//undefined 3 2 (5) [1, 2, 3, 4, 5]
//undefined 4 3 (5) [1, 2, 3, 4, 5]
//undefined 5 4 (5) [1, 2, 3, 4, 5]
})
上面的结果可以看到,currentValue 和 currentIndex 的值确实是从索引为 1 开始打印的,可是为什么 previousValue 的值除了第一次打印 1 ,其余全是 undefined
这里就是展现 reduce 作用的一部分,上面参数中说明了 previousValue 的值是上一次回调函数的返回值,上面的例子中没有返回值,那我们给他一个返回值
var arr = [1,2,3,4,5];
arr.reduce(function (previousValue,currentValue,currentIndex,array) {
console.log(previousValue,currentValue,currentIndex,array);
return previousValue + currentValue;
//1 2 1 (5) [1, 2, 3, 4, 5]
//3 3 2 (5) [1, 2, 3, 4, 5]
//6 4 3 (5) [1, 2, 3, 4, 5]
//10 5 4 (5) [1, 2, 3, 4, 5]
})
可以看到,previousVaule 确实打印了上一次的返回值,可是 reduce() 中每次从下标为 1 开始取值,还不如 for 循环适用,如何解决下标问题呢?
reduce() initialValue 参数
reduce() 除了callback 回调函数这个参数之外,还有一个 initiaValue 参数,这个参数是初始值的意思
- 初始值可以为任意值,相当于给 previousValue 赋值
- 当我们往 initiaValue 形参传值的时候, currentValue 和 currentIndex 的初始值不再是索引为 1 的值,而是 从索引为 0 开始找**(注意:传递任意值都会让初始值改变,只有 previousValue 来接收这个参)**
var arr = [1,2,3,4,5];
arr.reduce(function (previousValue,currentValue,currentIndex,array) {
console.log(previousValue,currentValue,currentIndex,array);
return previousValue + currentValue;
//0 1 0 (5) [1, 2, 3, 4, 5]
//1 2 1 (5) [1, 2, 3, 4, 5]
//3 3 2 (5) [1, 2, 3, 4, 5]
//6 4 3 (5) [1, 2, 3, 4, 5]
//10 5 4 (5) [1, 2, 3, 4, 5]
},0);//这里传了一个 0 作为参数,相当于 previousValue = 0;
如果我们传递一个空数组会得到什么结果?
var arr = [1,2,3,4,5];
var newArr = arr.reduce(function (previousValue,currentValue,currentIndex,array) {//因为最后一次调用的结果会返回出来,我们接受打印一下
console.log(previousValue,currentValue,currentIndex,array);
return previousValue + currentValue;
// [] 1 0 (5) [1, 2, 3, 4, 5]
// 1 2 1 (5) [1, 2, 3, 4, 5]
// 12 3 2 (5) [1, 2, 3, 4, 5]
// 123 4 3 (5) [1, 2, 3, 4, 5]
// 1234 5 4 (5) [1, 2, 3, 4, 5]
},[]);//这里传递了一个空数组
console.log(newArr);//123454
当我们传递空数组的时候,currentValue 和 currentIndex 都是从索引为 0 开始的,previousValue = []; 得到的结果不再是相加的值,而是字符串拼接**(注意:传递空数组,得到的是字符串拼接,并不是想象中的数组拼接)**
reduce() 常用技巧
- 数组求和、求积
var arr = [1,2,3,4,5];
//求和
var sum = arr.reduce(function(prev , value , index ){
return prev + value;//因为 prev 是每一次回调的值,所以这一句就相当于 prev = prev + value
},0);
console.log(sum);
//求积
var product = arr.reduce(function(prev , value , index){
return prev*value;//prev = prev*value
},1);//因为是求积,所以 prev 的初始值为 1
console.log(product);
- 数组中每个元素(或字母)出现的次数
因为 reduce 是数组的方法,字符串使用得先转换成数组
var arr = 'abbdfghdfg';
arr = arr.split('');//因为 reduce 是数组的方法,所以得先转换成数组
var obj = arr.reduce(function(prev , value , index){
if(value in prev){
prev[value]++;
}else{
prev[value] = 1;
}
return prev;
},{});//需要用对象的值去保存每个字母出现的次数,所以初始值为空对象
console.log(obj);//{a: 1, b: 2, d: 2, f: 2, g: 2, h:1}
- 数组去重
var arr = [1,2,4,4,5];
var newArr = arr.reduce(function(prev , value , index){
if(prev.indexOf(value) == -1){
prev.push(value);
}
return prev;
},[]);
console.log(newArr);//[1,2,4,5]因为通过 push() 方法添加的,所以返回的是数组
- 二维数组转为一维数组
这种方法只适用于数组元素全为数组
var arr = [[1,2],[3,4],[5,6]];
var newArr = arr.reduce(function(prev,value,index){
return prev.concat(value);
},[]);
console.log(newArr);//[1,2,3,4,5,6]
- 多维数组拍平
var arr = [1,[2,3],[4,[5,6]]];
function oneDimensional(arr){
return arr.reduce(function(prev,value,index){
return prev.concat(Array.isArray(value) ? oneDimensional(value) : value);
//用 prev 空数组去拼接每一个当前值,如果当前值为数组,就调用拍平函数,如果不是数组,就直接拼接
},[]);
}
var newArr = oneDimensional(arr);
console.log(newArr);//[1,2,3,4,5,6]
- 对象里的属性求和
var arr = [{
subject:'math',
score:50
},
{
subject:'chinese',
score:60
},
{
subject:'english',
score:55
}];
var sum = arr.reduce(function(prev,value,index){
return prev + value.score;
},0);
console.log(sum);//165