改变树形结构里的键值

const target = [{
    "title": "人物数据",
    "value": "",
    "children": [{
        "title": "本市常驻人员",
        "value": "361,123",
        "children": null
      },
      {
        "title": "本市暂住人员",
        "value": "361,123",
        "children": null
      },
      {
        "title": "本市流动人员",
        "value": "361,123",
        "children": null
      },
      {
        "title": "往来过省人员",
        "value": "361,123",
        "children": [{
            "title": "出境申请人员",
            "value": "361,123",
            "children": null
          },
          {
            "title": "火车过省人员",
            "value": "361,123",
            "children": null
          }
        ]
      }
    ]
  },
  {
    "title": "车辆数据",
    "value": "",
    "children": null
  }
]

有如下数据结构,如何将里面title都改为name呢,用递归的写法怎么也绕不过来,请高手指教。。

阅读 8.4k
5 个回答
function trans (data) {
  data.forEach(item => {
    item.name = item.title // 把title属性赋值给name属性
    delete item.title // 删除title属性

    item.children && trans(item.children) // 如果有children,递归调用
  })
}

trans(target)
console.log(target)
分两种情况递归,数组和对象

replace(target);

function replace(target) {
  if (target instanceof Array) {
    target.forEach(element => {
      replace(element);
    });
  } else if (target && typeof target === "object") {
    Object.keys(target).forEach(key => {
      if (target[key] && typeof target[key] === "object") {
        replace(target[key]);
      }
      if (key === 'title') {
        target['name'] = target[key];
        delete target['title'];
      }
    });
  } else {
    return;
  }
}
console.log(target);

先转成JSON字符串,在替换掉字符串的所有title属性,最后在转成字符串。

不过需要将const target 改成 let target

JSON.stringify(target).replace(/"title":/g,'"name":'))

如果你不喜欢这个方法,可以选择递归来解决。

已经有这么多答案了,都是不错的答案,不过授人以鱼不如授人以渔,我可以简单分享一下我自己写递归代码的经验,防止写懵逼,大体以下三点:

  • 先找递归中的子问题
  • 再找开始递归的条件
  • 再找结束递归的条件

按你的例子中,相应的应该是:

  • 将 title 替换为 name
  • 当前遍历对象有 children 属性且非空
  • 当前遍历对象没有 children 或者 children 属性为空

然后按着这个写个伪代码:

function recurse(node) {
    // 完成第一点要做的事情
    ...(替换 title 为 name 的代码)
    
    // 是否要开始递归
    if(node.children && node.children.length > 0) {
        // 递归...
        node.children.forEach(recurse)
    } else {
        // 不递归...
        return
    }
}

然后你就会发现,其实你只需要实现替换 title 为 name 的那部分代码了。

            function transferKey(arr){
                arr.forEach(obj => {
                    obj.name = obj.title
                    delete obj["title"]
                    if(obj.children instanceof Array){
                        transferKey(obj.children)
                    }
                })
                return arr
            }    
推荐问题