JavaScript实现保留父级属性的嵌套对象扁平化递归函数
通用多层嵌套结构扁平化转换实现方案
核心实现思路
你目前写的两层硬编码转换逻辑,本质是遍历每一层节点时,把当前节点的键值对和累计的父节点属性做合并,直到遍历到最内层的纯数据数组就输出结果。要适配任意固定深度的结构,只需要把这个遍历逻辑改成可自我调用的递归流程,不用为每一层单独写flatMap嵌套。
递归逻辑设计
递归函数接收两个参数:
- 第一个参数是当前待处理的节点数组,初始值为整个嵌套结构的根数组
- 第二个参数是累计继承到的父节点属性对象,初始值为空对象
函数内部的执行流程完全适配统一嵌套的结构约束: - 遍历当前传入的每个节点,提取节点上除
val外的所有固定层级键(也就是a、b、c等你提前定义的层级键),和累计的父属性做合并,生成新的属性上下文 - 判断当前节点的
val类型:如果val是纯数据数组(元素是数字/字符串等基础类型),说明到达了最内层,直接把合并好的属性上下文加上对应的val值,作为一条扁平结果 - 如果
val还是对象数组(存在更深层嵌套),就把这个val作为新的待处理节点数组,带着刚才合并好的属性上下文,递归调用自身继续处理下一层
可直接复用的完整代码
function flattenNested(nodeList, parentProps = {}) { const flatResult = []; nodeList.forEach(node => { // 合并父节点属性和当前节点的层级键(自动识别a/b/c等非val字段) const mergedProps = { ...parentProps }; Object.keys(node).forEach(key => { if (key !== 'val') { mergedProps[key] = node[key]; } }); // 判断是否到达最内层(val为基础类型数组) const firstValItem = node.val[0]; const isLeafLayer = typeof firstValItem !== 'object' || firstValItem === null; if (isLeafLayer) { // 最内层直接生成结果项 flatResult.push({ ...mergedProps, val: node.val }); } else { // 嵌套层递归处理 flatResult.push(...flattenNested(node.val, mergedProps)); } }); return flatResult; }
效果验证
两层结构测试
输入你提供的两层结构:
const twoLayerData = [ { a: "x", val: [ { b: "y1", val: [1, 2, 3] }, { b: "y2", val: [4, 5, 6] }, ], }, ]; console.log(flattenNested(twoLayerData));
输出和你预期的两层转换结果完全一致。
三层结构测试
输入你提供的三层结构:
const threeLayerData = [ { a: "x", val: [ { b: "y1", val: [ {c: "z1", val: [1, 2]} ] }, { b: "y2", val: [ { c: "z2", val: [3, 4] }, { c: "z3", val: [5, 6, 7] }, { c: "z4", val: [8] } ] }, ], }, ]; console.log(flattenNested(threeLayerData));
输出结果为:
[ { a: "x", b: "y1", c: "z1", val: [1, 2] }, { a: "x", b: "y2", c: "z2", val: [3, 4] }, { a: "x", b: "y2", c: "z3", val: [5, 6, 7] }, { a: "x", b: "y2", c: "z4", val: [8] } ]
完全符合继承所有父节点键值对的要求。
补充说明
因为你的结构约束是所有嵌套层级完全统一,这个实现不需要提前硬编码a、b、c的键名映射,只要满足“每层非val的键是固定的层级键、最内层val为纯数据数组”的规则,不管是4层、5层还是更多层的结构,都可以直接复用,不需要修改函数逻辑。
内容的提问来源于stack exchange,提问作者xy2_
相关产品推荐
相关产品推荐

