JavaScript樹形數(shù)據(jù)扁平化的三種實(shí)現(xiàn)方法(遞歸/迭代/flatMap)
在前端開發(fā)中,我們經(jīng)常會(huì)遇到 樹形結(jié)構(gòu)(Tree Data Structure) 的數(shù)據(jù),比如:
- 菜單列表(菜單 → 子菜單 → 孫菜單)
- 部門組織架構(gòu)(公司 → 部門 → 小組 → 員工)
- 樹狀分類(分類 → 子分類 → 子子分類)
而有時(shí)候,我們需要將樹形數(shù)據(jù)拍平成一維數(shù)組,方便做搜索、統(tǒng)計(jì)、映射等操作。
一、樹形結(jié)構(gòu)的特點(diǎn)
一個(gè)典型的樹形結(jié)構(gòu)數(shù)據(jù)可能是這樣的:
const treeData = [
{
id: 1,
name: "A",
children: [
{
id: 2,
name: "A-1",
children: [
{ id: 3, name: "A-1-1" },
{ id: 4, name: "A-1-2" }
]
},
{
id: 5,
name: "A-2"
}
]
},
{
id: 6,
name: "B"
}
];
特點(diǎn):
- 每個(gè)節(jié)點(diǎn)可能有
children屬性存放子節(jié)點(diǎn)。 - 層級(jí)關(guān)系不固定,可能有很多層。
- 數(shù)據(jù)訪問需要遞歸或迭代遍歷。
二、為什么要轉(zhuǎn)換成普通數(shù)組?
樹形結(jié)構(gòu)雖然表達(dá)了層級(jí)關(guān)系,但在以下場景下并不方便:
- 全局搜索:需要遍歷所有節(jié)點(diǎn)匹配關(guān)鍵字。
- 批量操作:需要一次性拿到所有節(jié)點(diǎn)的 ID 或名稱。
- 統(tǒng)計(jì):統(tǒng)計(jì)節(jié)點(diǎn)數(shù)量、節(jié)點(diǎn)類型等。
將樹形數(shù)據(jù)拍平成數(shù)組后,數(shù)據(jù)會(huì)變成這樣:
[
{ id: 1, name: "A" },
{ id: 2, name: "A-1" },
{ id: 3, name: "A-1-1" },
{ id: 4, name: "A-1-2" },
{ id: 5, name: "A-2" },
{ id: 6, name: "B" }
]
這樣處理起來就非常方便。
三、實(shí)現(xiàn)方法
方法一:遞歸實(shí)現(xiàn)
遞歸是處理樹形結(jié)構(gòu)的經(jīng)典方式。
function treeToArray(tree) {
let result = [];
function traverse(nodeList) {
for (const node of nodeList) {
// 拷貝當(dāng)前節(jié)點(diǎn)(防止修改原數(shù)據(jù))
const { children, ...rest } = node;
result.push(rest);
// 如果有子節(jié)點(diǎn),遞歸處理
if (children && children.length) {
traverse(children);
}
}
}
traverse(tree);
return result;
}
const flatArray = treeToArray(treeData);
console.log(flatArray);
運(yùn)行結(jié)果:
[
{ id: 1, name: 'A' },
{ id: 2, name: 'A-1' },
{ id: 3, name: 'A-1-1' },
{ id: 4, name: 'A-1-2' },
{ id: 5, name: 'A-2' },
{ id: 6, name: 'B' }
]
方法二:迭代(棧)實(shí)現(xiàn)
如果不想用遞歸,可以用棧來實(shí)現(xiàn)。
function treeToArrayIterative(tree) {
let result = [];
let stack = [...tree]; // 先把根節(jié)點(diǎn)放進(jìn)棧
while (stack.length) {
const node = stack.pop();
const { children, ...rest } = node;
result.push(rest);
// 注意:這里用棧,所以先放子節(jié)點(diǎn)才能保證順序
if (children && children.length) {
stack.push(...children);
}
}
return result;
}
const flatArray2 = treeToArrayIterative(treeData);
console.log(flatArray2);
方法三:使用 Array.flatMap(ES2019+)
如果層級(jí)不深,可以用 flatMap + 遞歸的方式更簡潔:
function treeToArrayFlatMap(tree) {
return tree.flatMap(({ children, ...rest }) =>
children ? [rest, ...treeToArrayFlatMap(children)] : [rest]
);
}
console.log(treeToArrayFlatMap(treeData));
四、性能對比
- 遞歸:代碼簡潔、可讀性好,適合絕大多數(shù)場景。
- 迭代:避免遞歸棧溢出,適合極深層級(jí)的樹。
- flatMap:語法簡潔,但瀏覽器兼容性略差(需 ES2019+)。
五、總結(jié)
樹形結(jié)構(gòu)轉(zhuǎn)換為普通數(shù)組的關(guān)鍵點(diǎn)在于:
- 遍歷:無論遞歸還是迭代,都需要訪問每一個(gè)節(jié)點(diǎn)。
- 數(shù)據(jù)處理:在 push 到結(jié)果數(shù)組時(shí),去掉
children,避免冗余。 - 順序:遞歸天然保證順序,迭代需要注意入棧順序。
在實(shí)際項(xiàng)目中,可以根據(jù)數(shù)據(jù)規(guī)模和瀏覽器兼容性選擇合適的方式。
建議
在處理樹形結(jié)構(gòu)時(shí),可以先封裝一個(gè)通用的遍歷方法,這樣后續(xù)不僅能拍平數(shù)組,還可以做任意數(shù)據(jù)加工,比如篩選、映射等。
到此這篇關(guān)于JavaScript樹形數(shù)據(jù)扁平化的三種實(shí)現(xiàn)方法(遞歸/迭代/flatMap)的文章就介紹到這了,更多相關(guān)JavaScript樹形數(shù)據(jù)扁平化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Javascript中扁平化數(shù)據(jù)結(jié)構(gòu)與JSON樹形結(jié)構(gòu)轉(zhuǎn)換詳解
- JavaScript前端面試扁平數(shù)據(jù)轉(zhuǎn)tree與tree數(shù)據(jù)扁平化
- JavaScript數(shù)據(jù)扁平化詳解
- 使用JavaScript將扁平數(shù)據(jù)轉(zhuǎn)換為樹形結(jié)構(gòu)的多種實(shí)現(xiàn)方法
- JavaScript 實(shí)現(xiàn)普通數(shù)組數(shù)據(jù)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)的步驟說明
相關(guān)文章
JavaScript forEach方法用法示例實(shí)戰(zhàn)
本文將詳細(xì)介紹forEach方法的基本概念、用法、常見的應(yīng)用場景、與其他遍歷方法的對比,并提供實(shí)戰(zhàn)示例,幫助您全面掌握這一強(qiáng)大的工具,感興趣的朋友跟隨小編一起看看吧2025-06-06
JavaScript中不可忽略的Symbol的盤點(diǎn)
Symbol類型的出現(xiàn),為每個(gè)屬性賦予了獨(dú)一無二的標(biāo)識(shí)符,無論項(xiàng)目多么復(fù)雜,Symbol都能確保屬性鍵的絕對唯一性,下面我們就來看看JavaScript中那些不可忽略的Symbol吧2024-12-12
JavaScript中的scrollTop詳解(滾動(dòng)到頂部)
scrollTop是JavaScript中一個(gè)非常有用且重要的方法,它用于獲取或設(shè)置元素的垂直滾動(dòng)條位置,這篇文章主要給大家介紹了關(guān)于JavaScript中scrollTop詳解(滾動(dòng)到頂部)的相關(guān)資料,需要的朋友可以參考下2023-12-12
JavaScript封裝LINQ查詢方法實(shí)戰(zhàn)
本文主要介紹了通過js-linq庫在JavaScript中實(shí)現(xiàn)類似.NET LINQ的查詢功能,封裝Where、Select、OrderBy等方法,提升數(shù)組和可迭代對象的數(shù)據(jù)處理效率與代碼可讀性2025-09-09
javascript設(shè)計(jì)模式--策略模式之輸入驗(yàn)證
策略模式中的策略就是一種算法或者業(yè)務(wù)規(guī)則,將這些策略作為函數(shù)進(jìn)行封裝,并向外提供統(tǒng)一的調(diào)用執(zhí)行,本文給大家介紹javascript設(shè)計(jì)模式--策略模式之輸入驗(yàn)證,需要的朋友參考下2015-11-11
微信小程序之?dāng)?shù)據(jù)緩存的實(shí)例詳解
這篇文章主要介紹了微信小程序之?dāng)?shù)據(jù)緩存的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-09-09
JavaScript實(shí)現(xiàn)清除首尾空白字符再進(jìn)行空白匹配
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)清除首尾空白字符再進(jìn)行空白匹配的相關(guān)方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2025-12-12
詳解bootstrap導(dǎo)航欄.nav與.navbar區(qū)別
本篇文章主要介紹了詳解bootstrap導(dǎo)航欄.nav與.navbar區(qū)別,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11
js使用setTimeout實(shí)現(xiàn)定時(shí)炸彈的方法
這篇文章主要介紹了js使用setTimeout實(shí)現(xiàn)定時(shí)炸彈的方法,涉及javascript中setTimeout方法的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-04-04

