
本文详细介绍了如何利用JavaScript的`Array.prototype.reduce`方法,将一个包含父子关系信息的扁平对象数组高效地转换为一个多层级嵌套的对象结构。通过巧妙运用空值合并赋值运算符(`??=`),我们能以简洁的方式处理多层级嵌套,构建出符合预期树状结构的复杂对象。
在现代JavaScript开发中,数据结构的转换是一项常见任务。有时,我们会遇到一种扁平化的数据表示,其中每个对象都通过一个parent字段来指示其父级,但我们最终需要一个多层级嵌套的对象来更好地反映其层级关系。本教程将深入探讨如何高效地实现这种转换,尤其是在处理2、3层甚至更多层级嵌套时遇到的挑战。
我们通常会从一个数组开始,其中每个元素都是一个包含key、value和parent属性的对象。parent字段指定了当前对象应该归属的父级key。如果parent为空,则表示该对象是顶级元素。
输入示例:
const data = [
    { "rank": 0, "key": "REPORTING PERIOD", "value": "2022", "parent": "" },
    { "rank": 0, "key": "SIGNATURE DATE", "value": "20211005", "parent": "" },
    { "rank": 0, "key": "HOUSE", "value": "", "parent": "" },
    { "rank": 1, "key": "OWNER DATA", "value": "", "parent": "HOUSE" },
    { "rank": 2, "key": "FIRST NAME", "value": "Joe", "parent": "OWNER DATA" },
    { "rank": 2, "key": "LAST NAME", "value": "Smith", "parent": "OWNER DATA" },
    // ... 更多数据
];期望的输出结构:
{
  "REPORTING PERIOD": "2022",
  "SIGNATURE DATE": "20211005",
  "HOUSE": {
    "OWNER DATA": {
      "FIRST NAME": "Joe",
      "LAST NAME": "Smith"
    },
    // ... 其他 HOUSE 内部的嵌套对象
  },
  // ... 其他顶级对象
}显而易见,挑战在于如何动态地创建和引用这些嵌套层级,确保每个子元素都能正确地放置在其父元素之下。
一种直观的尝试是遍历数组,根据parent字段将元素添加到结果对象中。
const resultObject = {};
for (const obj of data) {
    const { key, value, parent } = obj;
    if (parent === "" || parent === undefined) {
      resultObject[key] = value; // 顶级元素
    } else {
      // 如果父级不存在,创建一个空对象
      if (!resultObject[parent]) {
        resultObject[parent] = {};
      }
      // 将当前元素作为子属性添加到父级对象中
      (resultObject[parent])[key] = value;
    }
}
console.log(resultObject);这种方法的问题在于,它只能正确处理一级嵌套。例如,"FIRST NAME"的父级是"OWNER DATA",而"OWNER DATA"的父级是"HOUSE"。上述代码会将"FIRST NAME"直接添加到resultObject["OWNER DATA"]中,但resultObject["OWNER DATA"]本身可能还未被正确地嵌套到resultObject["HOUSE"]中,或者resultObject["OWNER DATA"]可能被错误地初始化为 {} 而不是作为HOUSE的子属性。它无法在一次循环中动态地追踪和构建任意深度的嵌套路径。
要高效地处理多层级嵌套,我们可以使用 Array.prototype.reduce 方法。reduce允许我们遍历数组并累积一个单一的结果。关键在于,我们可以利用reduce的累加器(accumulator)来同时作为我们构建的目标对象和查找父级节点的映射表。
核心思路:
示例代码:
const data = [
    {"rank":0,"key":"REPORTING PERIOD","value":"2022","parent":""},
    {"rank":0,"key":"SIGNATURE DATE","value":"20211005","parent":""},
    {"rank":0,"key":"HOUSE","value":"","parent":""},
    {"rank":1,"key":"OWNER DATA","value":"","parent":"HOUSE"},
    {"rank":2,"key":"FIRST NAME","value":"Joe","parent":"OWNER DATA"},
    {"rank":2,"key":"LAST NAME","value":"Smith","parent":"OWNER DATA"},
    {"rank":1,"key":"VALUE HISTORY","value":"","parent":"HOUSE"},
    {"rank":2,"key":"INITAL PRICE","value":"12345","parent":"VALUE HISTORY"},
    {"rank":2,"key":"LAST SALE PRICE","value":"1231236","parent":"VALUE HISTORY"},
    {"rank":1,"key":"ADDRESS","value":"","parent":"HOUSE"},
    {"rank":2,"key":"STREET 1","value":"5 MAIN TERRACE","parent":"ADDRESS"},
    {"rank":2,"key":"CITY","value":"LONDON","parent":"ADDRESS"},
    {"rank":0,"key":"AGENT","value":"","parent":""},
    {"rank":1,"key":"COMPANY DATA","value":"","parent":"AGENT"},
    {"rank":2,"key":"COMPANY NAME","value":"The Real Agent, Inc","parent":"COMPANY DATA"},
    {"rank":2,"key":"BUSINESS NUMBER","value":"0021690080","parent":"COMPANY DATA"},
    {"rank":1,"key":"BUSINESS ADDRESS","value":"","parent":"AGENT"},
    {"rank":2,"key":"STREET 1","value":"800 MENLO STREET, SUITE 100","parent":"BUSINESS ADDRESS"},
    {"rank":2,"key":"CITY","value":"MENLO PARK","parent":"BUSINESS ADDRESS"},
    {"rank":2,"key":"ZIP","value":"94025","parent":"BUSINESS ADDRESS"}
];
const tree = data.reduce((accumulator, { parent, key, value }) => {
  // 1. 确保父节点存在于累加器中,如果不存在则初始化为 {}
  // (accumulator[parent] ??= {}) 会返回 accumulator[parent] 的引用
  // 2. 在获取到的父节点引用上,设置当前 key 的值
  // 3. 如果当前 value 为空字符串,表示它是一个中间父节点,
  //    则将其值设置为一个新的空对象 (accumulator[key] ??= {}),
  //    以便后续的子节点可以添加到这个对象中。
  //    否则,直接赋值其 value。
  (accumulator[parent] ??= {})[key] = value === '' ? (accumulator[key] ??= {}) : value;
  return accumulator; // 返回更新后的累加器
}, {})['']; // 初始累加器为空对象,并最终取出 'parent: ""' 对应的顶级结构
// 注意:最后的 [''] 是为了从累加器中提取最终的根对象,
// 因为所有顶级元素 (parent 为 "") 都会被归类到 accumulator[''] 中。
console.log(JSON.stringify(tree, null, 2));代码解析:
通过巧妙地运用 Array.prototype.reduce 方法和 nullish coalescing assignment (??=) 运算符,我们可以高效且简洁地将一个扁平化的对象数组转换为任意深度的嵌套对象。这种模式在处理具有父子关系的数据转换时非常强大和灵活,是JavaScript开发中一个值得掌握的技巧。理解其工作原理不仅能解决当前问题,还能为处理其他复杂数据结构转换提供思路。
以上就是将扁平对象数组转换为多层级嵌套对象的详细内容,更多请关注php中文网其它相关文章!
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
                
                                
                                
                                
                                
                                
                                Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号