(一)reduce的作用
1 . 数组求和,求乘积
2 . 计算数组中每个元素出现的次数
3 . 数组去重
4 . 数组扁平化(将二维,或者多维数组转化为一维数组)
等等等等…基本上数组方法能做的事情,reduce都能做
大部分现代的数组方法都返回一个新的数组,而 Array.reduce() 更加灵活。它可以返回任意值,它的功能就是将一个数组的内容聚合成单个值。这个值可以是数字、字符串,甚至可以是对象或新数组
(二)reduce的参数
reduce的参数,只接收两个参数,1. 回调函数(必填),2. initValue 初始值(非必填)
注意:回调函数有四个参数
对空数组调用reduce()和reduceRight()是不会执行其回调函数的,可认为reduce()对空数组无效
1 . Accumulator (累计器),上一次回调函数的返回值,如果有initValue,他就表示为initValue的值
2 . Current Value 当前正在处理的数组元素
3 . Current Index 当前正在处理的数组元素的索引,如果提供了initValue ,则索引值为0,否则索引值为1
4 . Source Array 源数组
const numArr = [1, 2, 3, 4, 5]
const sum = numArr.reduce(function (accumulator, currentValue, currentIndex, array) {
console.log(accumulator, currentValue)
return accumulator + currentValue;
})
// 这里因为没有init值,所以输出,1 2(没有init时,循环 length - 1 次)
const numArr = [1, 2, 3, 4, 5]
const sum = numArr.reduce(function (accumulator, currentValue, currentIndex, array) {
console.log(accumulator, currentValue)
return accumulator + currentValue;
}, 5)
// 这里因为有init值,所以输出,5 1(有init时,循环 length 次)
(三)利用reduce,求数组内所有元素的和,积 ,最大值,最小值
求和
const numArr = [1, 2, 3, 4, 5]
const sum = numArr.reduce((pre, cur, index, arr) => {
return pre + cur
})
// 封装成函数
function Accumulation(val) {
return val.reduce((pre, cur) => pre + cur);
}
console.log(Accumulation(numArr)) // 15
求积(跟求和一样,就是把 + 换成 * )
const numArr = [1, 2, 3, 4, 5]
const sum = numArr.reduce((pre, cur, index, arr) => {
return pre * cur
})
// 封装成函数
function Multiplication(val) {
return val.reduce((pre, cur) => pre * cur);
}
console.log(Multiplication(numArr)) // 120
求最大值
const numArr = [12, 45, 21, 65, 38, 76, 108, 43];
function maxNum(arr = []) {
return arr.reduce((pre, cur) => pre > cur ? pre : cur)
}
求最小值
const numArr = [12, 45, 21, 65, 38, 76, 108, 43];
function maxNum(arr = []) {
return arr.reduce((pre, cur) => pre < cur ? pre : cur)
}
(四)利用reduce,计算数组中每个元素出现的次数
const nameArr = ['佩可莉姆', '可可萝', '凯露', '可可萝', '真步', '佩可莉姆', '可可萝']
// 设置一个初始值,init为空对象{}
const sum = nameArr.reduce((pre, cur, index, arr) => {
// 如果:当前值在上次的返回值中,则让他的value值++
// pre[cur] 相当于 obj.key
if (cur in pre) {
pre[cur]++
}
// 否则: pre[cur] = 1 的意思类比于 obj.key = value
// 因为这是 else 的值,这个 key,肯定不在这个对象中,如果一个对象的不存在这个 key ,我们又用obj.key的形式声明
// 则会直接给该对象添加属性,并赋值
else {
pre[cur] = 1
}
return pre;
}, {})
// { 佩可莉姆: 2, 可可萝: 3, 凯露: 1, 真步: 1 }
// 封装成函数
function Count(arr = []) {
return arr.reduce((pre, cur) => (pre[cur] = (pre[cur] || 0) + 1, pre), {});
}
如果你看不懂封装成函数的这段代码,下面是解释
1 . 逗号表达式(逗号运算符)逗号运算符是二元运算符,它能够先执行运算符左侧的操作数,然后再执行右侧的操作数,最后返回最右侧操作数的值。
举个例子:
与条件运算符、逻辑运算符根据条件来决定是否执行所有或特定操作数不同,逗号运算符会执行所有的操作数,但不会返回所有操作数的结果,它只返回最后一个操作数的值。(也就是例子中的 x * 8)
const exampleNum = (x = 5 + 3, x = x - 4, x * 8)
console.log(exampleNum) // 32
const nameArr = ['佩可莉姆', '可可萝', '凯露', '可可萝', '真步', '佩可莉姆', '可可萝']
// 封装成函数
function Count(arr = []) {
// 第一次循环 pre = {},cur = '佩可莉姆'
// 第二次循环 pre = { '佩可莉姆':1 } , cur = '可可萝'
// 第三次循环同理 结束时 pre = { '佩可莉姆':1 , '可可萝':1, '凯露':1}
// 第四次循环 开始时 pre = { '佩可莉姆':1 , '可可萝':1, '凯露':1}
return arr.reduce((pre, cur) => (
// 第一次循环 {}.佩可莉姆 = {}.佩可莉姆 || 0 因为此时,{}.佩可莉姆 = undefined 所以这里 = 0 + 1
// 然后返回 pre 也就是 { '佩可莉姆':1 }
// 第二次循环 { '佩可莉姆':1 }.可可萝 = { '佩可莉姆':1 }.可可萝 || 0,同理 { '佩可莉姆':1 }.可可萝 = undefined,所以这里 = 0 + 1
// 然后返回 pre 也就是 { '佩可莉姆':1 , '可可萝':1}
// 第四次循环 { '佩可莉姆':1 , '可可萝':1, '凯露':1}.可可萝 = { '佩可莉姆':1 , '可可萝':1, '凯露':1}.可可萝 || 0 ,
// 这时 { '佩可莉姆':1 , '可可萝':1, '凯露':1}.可可萝 = 1 已经有值了,不会走||运算了,之后再 + 1
// 然后返回 pre 也就是 { '佩可莉姆':1 , '可可萝':2, '凯露':1 }
pre[cur] = (pre[cur] || 0) + 1, pre
), {});
}
(五)数组扁平化
Array.concat()可以传入数组,也可以传入值
(数组扁平化Array.flat(Infinity)数组自带扁平化的方法,但是兼容性不太好,IE浏览器更是一点都不兼容,但是新版本的IE(Edge)却可以完美支持)
const numArr = [1, [2, [3, [4, [5]]]], 6]
const newArr = (arr) => {
return arr.reduce((pre, cur) => {
return pre.concat(Array.isArray(cur) ? newArr(cur) : cur)
}, [])
}
// 封装成函数
function myFlat(arr = []) {
return arr.reduce((pre, cur) => pre.concat(Array.isArray(cur) ? myFlat(cur) : cur), [])
}
(六)数组去重
const nameArr = ['佩可莉姆', '可可萝', '凯露', '可可萝', '真步', '佩可莉姆', '可可萝']
function myUnique(arr = []) {
return arr.reduce((pre, cur) => pre.includes(cur) ? pre : [...pre, cur], [])
}
(七)数组对象去重
const arrObj = [{ name: '小明' }, { name: '小红' }, { name: '小兰' }, { name: '小明' }, { name: '小兰' }];
// 定义一个空对象,用来保存第一次循环的对象的值,第二次时啥也不处理处理
const obj = {};
const newArr = arrObj.reduce((pre, cur, index) => {
// 将需要去重的字段值作为obj的key,判断obj上是否存在这个key的值,如【小明】这个key,存在则啥也不干,跳过这次循环
// 进入下次循环,否则,将这个key值设置为true,如obj.小明=true,同时,将这个值push给pre最后返回
obj[cur.name] ? '' : (obj[cur.name] = true && pre.push(cur));
return pre;
}, []);
(八)斐波那契数列
存在一个问题,输入小于2的数,都会返回 [0,1],这个问题可以根据自己的情况修改
function myFibonacci(time = 2) {
const Arr = [...new Array(time).keys()]
return Arr.reduce((pre, cur, index) => {
index > 1 && pre.push(pre[index - 1] + pre[index - 2])
return pre
}, [0, 1])
}
console.log(myFibonacci(1)) // [0, 1]
console.log(myFibonacci(2)) // [0, 1]
console.log(myFibonacci(10)) // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]