本文介绍如何使用 JavaScript 将扁平的对象数组(每个对象含 key 和空 children 数组)转化为单链式深度嵌套对象,核心是逆序遍历 + reduce 构建父子引用关系。
本文介绍如何使用 javascript 将扁平的对象数组(每个对象含 `key` 和空 `children` 数组)转化为单链式深度嵌套对象,核心是逆序遍历 + `reduce` 构建父子引用关系。
在实际开发中,我们常需将线性数据结构(如菜单项、路径节点、配置层级)动态组装为树形嵌套结构。例如,给定一个顺序明确的对象数组:
const list = [
{ key: "key1", children: [] },
{ key: "key2", children: [] },
{ key: "key3", children: [] }
];
目标是生成如下单路径嵌套对象(即 key1 的 children 包含 key2,key2 的 children 包含 key3,以此类推):
[
{
key: "key1",
children: [
{
key: "key2",
children: [
{
key: "key3",
children: []
}
]
}
]
}
]
⚠️ 注意:原始尝试中正向循环并反复向 list[0].children 推入后续元素,会导致所有子项被平铺在同一层,破坏层级逻辑。正确解法的关键在于 从后往前建立父子引用 —— 即让后一个元素成为前一个元素的 children 唯一成员。
推荐使用 Array.prototype.reverse() 配合 reduce() 实现声明式构建:
const list = [
{ key: "key1", children: [] },
{ key: "key2", children: [] },
{ key: "key3", children: [] }
];
// ✅ 正确实现:逆序处理,逐级挂载
const result = list
.slice() // 避免修改原数组
.reverse()
.reduce((acc, current, index, arr) => {
if (index === arr.length - 1) {
// 最后一个(即原数组第一个)作为根,直接加入结果
acc.push(current);
} else {
// 将当前项设为下一个(在原顺序中更靠前)元素的 children
arr[index + 1].children = [current];
}
return acc;
}, []);
console.log(JSON.stringify(result, null, 2));
// 输出:
// [
// {
// "key": "key1",
// "children": [
// {
// "key": "key2",
// "children": [
// {
// "key": "key3",
// "children": []
// }
// ]
// }
// ]
// }
// ]
? 关键要点说明:
- slice() 用于浅拷贝原数组,确保函数式纯度,不污染输入;
- reverse() 后,原 [key1, key2, key3] 变为 [key3, key2, key1],此时索引 i 对应的元素应成为 i+1 元素的子节点;
- reduce 的初始值为 [],仅在处理到最后一个元素(即 arr.length - 1,对应原数组首项)时将其推入结果;其余情况均执行 arr[i + 1].children = [current],完成反向挂载;
- 此方案时间复杂度为 O(n),空间复杂度为 O(1)(除输出外),简洁高效。
? 扩展建议:
若需支持多分支树或更复杂键名(如 id/parentId),应改用哈希表预构建映射关系;但对严格线性、单路径嵌套场景,上述逆序 reduce 是最直观、低开销的标准解法。










