作用:
- 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值
语法:
reduce(callback, initValue)
参数:
- callback:(accumulator,currentValue,index, array)
- initValue:初始值
返回值: 函数累计处理的结果
相对于forEach,其实reduce仅仅多了个initValue,我们用例子来证明
例子1:求和
求下面数组中isTrue为true的总价格
let arr = [
{ price: 100, brand: '凤凰',num: 2, isTrue: true },
{ price: 1000, brand: '捷安特', num: 3, isTrue: false },
{ price: 500, brand: '迪卡侬', num: 1, isTrue: true }
]
我看先看看用forEach怎么做
let total = 0
arr.forEach(v => {
if (v.isTrue) {
total += v.price * v.num
}
})
console.log(total)
再看看用reduce
let total = arr.reduce((acc, pre) => {
if (pre.isTrue) {
return acc += pre.num * pre.price
} else {
return acc
}
}, 0)
console.log(total)
简写为
console.log(arr.reduce((acc, pre) => acc + (pre.isTrue ? pre.num * pre.price : 0), 0))
看到这个例子大家可以看到reduce其实就是比forEach少声明了一个total,其实这个例子reduce返回的就是total
注意: reduce的第二个参数如果不写就默认是数组的第一项
例子2:计算数组中每个元素出现的次数
let names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
const nameNum = names.reduce((acc, pre) => {
if (pre in acc) {
acc[pre]++
} else {
acc[pre] = 1
}
return acc
}, {})
console.log(nameNum)
例子3:数组去重
let a1 = [1, 2, 3, 4, 4, 1]
let newArr = a1.reduce((acc, pre) => {
if (acc.includes(pre)) {
return acc
} else {
return acc.concat(pre)
}
}, [])
console.log(3, newArr)
// 简写
a1.reduce((acc,pre) => acc.concat(acc.includes(pre) ? [] : pre), [])
例子4:将二维数组转化为一维
let a2 = [[0, 1], [2, 3], [4, 5]]
let singleArr = a2.reduce((acc, pre) => acc.concat(pre), [])
console.log(4, singleArr)
例子5: 将多维数组转化为一维数组
let a3 = [[0, 1], [2, 3], [4, [5, 6, 7]]]
function transformArr(arr) {
return arr.reduce((acc, pre) => {
if (Array.isArray(pre)) {
return acc.concat(transformArr(pre))
} else {
return acc.concat(pre)
}
}, [])
}
console.log(transformArr(a3))
例子6:多维转一维数组(内含对象)
const arr = [
{ id: 1, p_id: 0, name: '首页',
children: [
{ id: 4, p_id: 1, name: '权限管理',
children: [
{ id: 6, p_id: 4, name: '角色列表',
children: [
{ id: 5, p_id: 6, name: '管理员列表',
},
],
},
],
},
],
},
{ id: 2, p_id: 0, name: '菜单管理' },
{ id: 3, p_id: 0, name: '菜单列表' }
]
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => {
// if (Array.isArray(cur.children)) {
// // acc = acc.concat(cur)
// // return acc.concat(newArrFn(cur.children))
// return acc.concat(cur, newArrFn(cur.children))
// } else {
// return acc.concat(cur)
// }
// }, [])
// }
// function newArrFn(arr) {
// return arr.reduce((acc, cur) => acc.concat(cur, Array.isArray(cur.children) ? // newArrFn(cur.children) : []), [])
// }
// 得到的新数组的对象中含有children属性,需要删除
function newArrFn(arr) {
return arr.reduce((acc, cur) => {
if (Array.isArray(cur.children)) {
const copyCur = { ...cur }
delete copyCur.children
return acc.concat(copyCur, newArrFn(cur.children))
} else {
return acc.concat(cur)
}
}, [])
}
console.log(newArrFn(arr))
例子7:一维数组转树形结构
let arr = [
{ id: 1, p_id: 0, name: '首页' },
{ id: 2, p_id: 0, name: '菜单管理' },
{ id: 3, p_id: 0, name: '菜单列表' },
{ id: 4, p_id: 1, name: '权限管理' },
{ id: 5, p_id: 6, name: '管理员列表' },
{ id: 6, p_id: 4, name: '角色列表' }
]
// 思路:
// 1、从数组arr中取出 p_id = 0 的数据 arr_pid0 存到数组中
// 2、然后找他的children,怎么找children呢?
// 3、假设arr_pid0 的 id 为 1,那么我要从arr中取出p_id = 1的数据赋值给children就可以了
// 4、然而咱们的函数就是从arr中取出 p_id === rootValue 的值
// 5、所以const children = newArrFn(arr, cur.id)
// 6、cur.children = children
function newArrFn(arr, rootValue = 0) {
return arr.reduce((acc, cur) => {
if (cur.p_id === rootValue) {
const children = newArrFn(arr, cur.id)
if (children.length) {
cur.children = children
}
acc.push(cur) // 返回值 新数组的长度
}
return acc
}, [])
}
console.log(newArrFn(arr))