JS使用reduce()方法處理樹形結(jié)構(gòu)數(shù)據(jù)
定義
reduce() 方法對(duì)數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回值。
reduce() 與forEach()、map()、filter()這些方法一樣,也會(huì)對(duì)數(shù)組中的每一項(xiàng)進(jìn)行遍歷,但是reduce() 可以將遍歷的前一個(gè)數(shù)組項(xiàng)產(chǎn)生的結(jié)果與當(dāng)前遍歷項(xiàng)進(jìn)行運(yùn)算。
語(yǔ)法
array.reduce(function(prev, cur, index, array){
...
}, init);
回調(diào)函數(shù)中的參數(shù):
- prev 必需。表示調(diào)用回調(diào)時(shí)的返回值,或者初始值 init。
- cur 必需。表示當(dāng)前元素。
- index 可選。表示當(dāng)前元素的索引。
- array 表示原數(shù)組。
- init 可選。初始值,作為第一次調(diào)用回調(diào)函數(shù)的第一個(gè)參數(shù)。
其中常用參數(shù):prev 和 cur
注意:回調(diào)函數(shù)第一次執(zhí)行時(shí),prev和cur的取值有兩種情況:如果調(diào)用reduce()時(shí)提供了初始值init,prev取init值,cur取數(shù)組中的第一個(gè)值,此時(shí)索引從0開始;如果沒(méi)有提供初始值init,則prev取數(shù)組中的第一個(gè)值,cur取數(shù)組中的第二個(gè)值,此時(shí)索引從1開始。
實(shí)例
1. 沒(méi)有傳遞初始值init
const arr = [1, 3, 5, 7]
arr.reduce(function(prev, cur, index, arr){
console.log(prev, cur, index)
return prev + cur
})
每次調(diào)用的參數(shù)和返回值如下表:
| callback | prev | cur | index | array | return value |
|---|---|---|---|---|---|
| 第1次 | 1 | 3 | 1 | [1, 3, 5, 7] | 4 |
| 第2次 | 4 | 5 | 2 | [1, 3, 5, 7] | 9 |
| 第3次 | 9 | 7 | 3 | [1, 3, 5, 7] | 16 |
因?yàn)闆](méi)有傳入初始值,所以索引是從1開始,callback被調(diào)用三次,開始時(shí)prev的值為數(shù)組第一項(xiàng)1,cur的值為3,相加之后返回值4作為下一輪回調(diào)的prev值,然后繼續(xù)下一輪的回調(diào),直至完成后返回。
2. 傳遞初始值的情況下
const arr = [1, 3, 5, 7]
arr.reduce(function(prev, cur, index, arr){
console.log(prev, cur, index)
return prev + cur
}, 10)
每次調(diào)用的參數(shù)和返回值如下表:
| callback | prev | cur | index | array | return value |
|---|---|---|---|---|---|
| 第1次 | 10 | 1 | 0 | [1, 3, 5, 7] | 11 |
| 第2次 | 11 | 3 | 1 | [1, 3, 5, 7] | 14 |
| 第3次 | 14 | 5 | 2 | [1, 3, 5, 7] | 19 |
| 第4次 | 19 | 7 | 3 | [1, 3, 5, 7] | 26 |
3. 數(shù)組去重
const arr = ['ab', 'v', 'd', 'ab', 'h', 'e', 'dc', 'e', 'e', 'f']
const newArr = arr.reduce(function(prev, cur){
!prev.includes(cur) && prev.push(cur)
return prev
}, [])
console.log(newArr) // ["ab", "v", "d", "h", "e", "dc", "f"]
執(zhí)行的步驟如下:
- 初始化一個(gè)空數(shù)組
- 第一次調(diào)用時(shí),prev 為初始值即空數(shù)組,cur 為數(shù)組中的第一項(xiàng) arr[1],然后在 prev 中查找 cur 是否已經(jīng)存在,如果不存在就將該項(xiàng)添加到 prev 中,并 prev 返回進(jìn)入下一次回調(diào)
- 第二次回調(diào)時(shí),prev 為第一次的返回值,cur 為數(shù)組中的第二項(xiàng) arr[2],然后在 prev 中查找 cur 是否已經(jīng)存在,如果不存在就將該項(xiàng)添加到 prev 中,并 prev 返回進(jìn)入下一次回調(diào)
- 最后將 prev 這個(gè)數(shù)組返回
4. 利用 reduce 對(duì)數(shù)組中的 Object 對(duì)象進(jìn)行分組及合并
//從后臺(tái)獲取的對(duì)象數(shù)組,根據(jù)對(duì)象的type進(jìn)行分組合并成tree樹形展示數(shù)據(jù)
const dataArr = [
{ type: '治理層', name: 'hive_82', reserve: '2', id: 1 },
{ type: '原始數(shù)據(jù)層', name: 'qwe', reserve: '1', id: 2 },
{ type: '貼源層', name: 'mysql_exchangis', reserve: '3', id: 3 },
{ type: '治理層', name: 'links_188', reserve: '1', id: 4 },
{ type: '貼源層', name: 'mysql_ces', reserve: '2', id: 5 }
]
const treeData = dataArr.reduce((cur, next) => {
const obj = cur.find(curItem => curItem.label === next.type)
if (obj) {
if (obj.children.indexOf(next.id) === -1) { //去重處理
obj.children.push({
...next,
label: next.name
})
}
} else {
const newObj = {
label: next.type,
children: [{
...next,
label: next.name
}]
}
cur.push(newObj)
}
return cur
}, [])
// 合并后的結(jié)果:
treeData = [
{
label: '治理層',
children: [
{ type: '治理層', name: 'hive_82', reserve: '2', id: 1, label: 'hive_82' },
{ type: '治理層', name: 'links_188', reserve: '1', id: 4, label: 'links_188' }
]
},
{
label: '原始數(shù)據(jù)層',
children: [
{ type: '原始數(shù)據(jù)層', name: 'qwe', reserve: '1', id: 2, label: 'qwe' }
]
},
{
label: '貼源層',
children: [
{ type: '貼源層', name: 'mysql_exchangis', reserve: '3', id: 3, label: 'mysql_exchangis' },
{ type: '治理層', name: 'mysql_ces', reserve: '2', id: 5, label: 'mysql_ces' }
]
}
]
5. 利用 reduce 處理菜單后端返回的菜單結(jié)構(gòu)
需要根據(jù) parentId 將這些數(shù)據(jù)轉(zhuǎn)換成層級(jí)結(jié)構(gòu)。
方法一:
const dataArr = [
{id: '18', name: '重置密碼', parentId: '30',parentName: '用戶管理'},
{id: '13', name: '審計(jì)日志', parentId: '29', parentName: '系統(tǒng)管理'},
{id: '29', name: '系統(tǒng)管理', parentId: '0', parentName: null},
{id: '14', name: '修改', parentId: '33', parentName: '部門管理'},
{id: '2', name: '用戶列表', parentId: '30', parentName: '用戶管理'},
{id: '30', name: '用戶管理', parentId: '29', parentName: '系統(tǒng)管理'},
{id: '33', name: '部門管理', parentId: '0', parentName: null},
{id: '37', name: '添加用戶', parentId: '30', parentName: '用戶管理'},
{id: '6', name: '添加', parentId: '33', parentName: '部門管理'},
{id: '7',name: '刪除', parentId: '33', parentName: '部門管理'}
]
//創(chuàng)建菜單id的映射關(guān)系
const idMapping = dataArr.reduce((prev, next, i) => {
prev[next.id] = i
return prev
}, {})
const treeData = []
dataArr.map(el => {
// 一級(jí)菜單
if (el.parentId === '0') {
treeData.push(el)
return
}
// 通過(guò)映射找到父元素
const parentEl = dataArr[idMapping[el.parentId]]
// 把當(dāng)前元素添加到父元素的`children`數(shù)組中
parentEl.children = [...(parentEl.children || []), el]
})
console.log(treeData)
方法二:
//根據(jù)parentId創(chuàng)建映射關(guān)系
const result = dataArr.reduce((prev, next) => {
prev[next.parentId] ? prev[next.parentId].push(next) : prev[next.parentId] = [next];
return prev;
}, {});
Object.keys(result).map(key => {
result[key].map((item, i) => {
result[item.id] ? item.children = result[item.id] : ''
});
})
this.treeData = result[0]
console.log(treeData)
還可以通過(guò)遞歸的方法來(lái)實(shí)現(xiàn),具體就不贅述了
最后生成的數(shù)據(jù)結(jié)構(gòu)如下圖所示:

以上就是JS使用reduce()方法處理樹形結(jié)構(gòu)數(shù)據(jù)的詳細(xì)內(nèi)容,更多關(guān)于JS的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- JavaScript中reduce()方法的使用詳解
- js中的reduce()函數(shù)講解
- 詳解JavaScript中數(shù)組的reduce方法
- 詳解JS數(shù)組Reduce()方法詳解及高級(jí)技巧
- js數(shù)組方法reduce經(jīng)典用法代碼分享
- JavaScript中自帶的 reduce()方法使用示例詳解
- JavaScript中reduce()的5個(gè)基本用法示例
- JavaScript中reduce()詳解及使用方法
- JS數(shù)組方法reduce的妙用分享
- JavaScript中的reduce方法執(zhí)行過(guò)程、使用場(chǎng)景及進(jìn)階用法
相關(guān)文章
javascript 折半查找字符在數(shù)組中的位置(有序列表)
折半查找字符在數(shù)組中的位置(有序列表),需要的朋友可以參考下。2010-12-12
Javascript 兩種刷新方法以及區(qū)別和適用范圍
這篇文章主要介紹了Javascript 兩種刷新方法以及區(qū)別和適用范圍的相關(guān)資料,需要的朋友可以參考下2017-01-01
JavaScript 動(dòng)態(tài)添加腳本,并觸發(fā)回調(diào)函數(shù)的實(shí)現(xiàn)代碼
JavaScript 動(dòng)態(tài)添加腳本,并觸發(fā)回調(diào)函數(shù)的實(shí)現(xiàn)代碼,需要的朋友可以參考下。2011-01-01
ES6?關(guān)鍵字?let?和?ES5?及關(guān)鍵字?var?的區(qū)別解析
var可以穿透控制語(yǔ)句、條件語(yǔ)句這樣的作用域,導(dǎo)致變量沖突經(jīng)常發(fā)生,這篇文章主要介紹了ES6?關(guān)鍵字?let?和?ES5?及關(guān)鍵字?var?的區(qū)別,需要的朋友可以參考下2022-09-09
JS實(shí)現(xiàn)為表格動(dòng)態(tài)添加標(biāo)題的方法
這篇文章主要介紹了JS實(shí)現(xiàn)為表格動(dòng)態(tài)添加標(biāo)題的方法,涉及javascript中createCaption方法添加標(biāo)題的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
js點(diǎn)擊出現(xiàn)場(chǎng)層層外點(diǎn)擊層消失的代碼
主要是修復(fù)了如果層上有東東的話,點(diǎn)擊也消失的情況2008-09-09

