JavaScript扁平化树形菜单需递归或栈遍历:递归法简洁常用,用reduce提取节点并展开children;深层时改用栈避免溢出,逆序入栈后reverse保序;注意children字段名差异及null/undefined健壮处理。

JavaScript 中对接口返回的树形菜单数据进行深度扁平化,核心是递归遍历每个节点及其 children(或类似字段),把所有层级的节点一次性提取到一个一维数组中。
明确树形结构特征
常见菜单接口返回的数据结构类似:
{
id: 1,
name: "系统管理",
children: [
{
id: 2,
name: "用户管理",
children: [
{ id: 3, name: "新增用户" },
{ id: 4, name: "编辑用户" }
]
}
]
}关键点:节点可能有 children 字段,且该字段为数组;子节点结构与父节点一致;层级不确定(可能很深)。
使用递归 + 展开语法(推荐)
简洁、可读性强,适合大多数场景:
- 定义一个函数,接收节点数组和可选的父级信息(如
parentId、level) - 对每个节点,先将其本身加入结果数组
- 若存在
children且不为空,则递归调用自身,传入子节点数组 - 利用扩展运算符
[...result, ...recursive(children)]或push(...)合并
示例代码:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
function flattenMenu(nodes, parentId = null, level = 0) {
if (!Array.isArray(nodes)) return [];
<p>return nodes.reduce((acc, node) => {
const { children, ...rest } = node;
acc.push({
...rest,
parentId,
level
});</p><pre class="brush:php;toolbar:false;">if (Array.isArray(children) && children.length > 0) {
acc.push(...flattenMenu(children, node.id, level + 1));
}
return acc;}, []); }
// 调用 const flatList = flattenMenu(menuData); // menuData 是接口返回的根数组
使用栈模拟递归(避免深层调用栈溢出)
当菜单层级极深(比如 1000+ 层),递归可能导致栈溢出,此时可用显式栈代替:
- 初始化一个栈,存入带上下文的节点(如
{ node, parentId, level }) - 循环出栈,处理当前节点,推入其每个子节点(更新
parentId和level) - 用数组收集所有已处理节点
示例代码:
function flattenMenuIterative(nodes, parentId = null, level = 0) {
if (!Array.isArray(nodes)) return [];
<p>const stack = nodes.map(node => ({ node, parentId, level }));
const result = [];</p><p>while (stack.length > 0) {
const { node, parentId, level } = stack.pop();
const { children, ...rest } = node;</p><pre class="brush:php;toolbar:false;">result.push({ ...rest, parentId, level });
if (Array.isArray(children) && children.length > 0) {
// 逆序入栈,保证原始顺序(可选)
for (let i = children.length - 1; i >= 0; i--) {
stack.push({
node: children[i],
parentId: node.id,
level: level + 1
});
}
}}
return result.reverse(); // 恢复原顺序(若需) }
补充说明与建议
实际项目中注意以下几点:
- 字段名可能不是
children,比如subMenus、list,需根据接口文档调整 - 有些后端会返回带环引用或空 children(
null或undefined),建议加健壮性判断:children?.length - 如需保留路径信息(如
path: "/system/user"),可在递归时拼接parentPath + '/' + node.code - 如果只是渲染用,不一定要完全扁平化——部分 UI 组件(如 Ant Design 的
Tree)直接支持嵌套结构
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










