递归+遍历对象和数组,替换对象的key

471 阅读4分钟

需求

替换对象里面的字段,而且里面有不确定层级的数值,里面再次嵌套对象,原始数据代码如下:

const targetObj =  {
  companyCnt: 2317547,
  industryCnt: 23,
  industryCode: "105",
  level: 1,
  name: "5G产业",
  downstream: [
    {
      downstream: [
        { industryCode: "1050101", level: 3, name: "网络规划/设计" },
        { industryCode: "1050102", level: 3, name: "网络工程/优化" },
      ],
      industryCnt: 3,
      industryCode: "10501",
      level: 2,
      name: "支撑层",
    },
    {
      downstream: [
        { industryCode: "1050201", level: 3, name: "芯片" },
        { industryCode: "1050202", level: 3, name: "射频器件" },
        { industryCode: "1050203", level: 3, name: "关键材料" },
      ],
      industryCnt: 4,
      industryCode: "10502",
      level: 2,
      name: "基础层",
    },
    {
      downstream: [
        { industryCode: "1050301", level: 3, name: "主设备" },
        { industryCode: "1050302", level: 3, name: "基站天线" },
        { industryCode: "1050303", level: 3, name: "SDN/NFV解决方案" },
        { industryCode: "1050304", level: 3, name: "光纤光缆" },
        { industryCode: "1050305", level: 3, name: "射频滤波器" },
        { industryCode: "1050306", level: 3, name: "光模块/光器件" },
        { industryCode: "1050307", level: 3, name: "小基站" },
        { industryCode: "1050308", level: 3, name: "基站配套" },
      ],
      industryCnt: 9,
      industryCode: "10503",
      level: 2,
      name: "传输层",
    },
    {
      downstream: [
        { industryCode: "1050401", level: 3, name: "系统集成" },
        { industryCode: "1050402", level: 3, name: "网络优化/维护" },
        { industryCode: "1050403", level: 3, name: "运营商" },
        { industryCode: "1050404", level: 3, name: "移动终端设备" },
        { industryCode: "1050405", level: 3, name: "其他应用层" },
      ],
      industryCnt: 6,
      industryCode: "10504",
      level: 2,
      name: "应用层",
    },
  ],
};

需要把对象以及内部不确定层级的key进行替换,替换规则是industryCode 换成 id , downstream 换成children , name 换成 label,也就是说不管,层级嵌套多少都要把对象内相应的字段进行替换。实现的输出代码如下:

{
      companyCnt: 2317547,
      industryCnt: 23,
      id: "105",// industryCode ==> id
      level: 1,
      label: "5G产业",//  name ==> label
      children: [ //  downstream ==> children
        {
          children: [
                { id: "1050101", level: 3, label: "网络规划/设计" },
                { id: "1050102", level: 3, label: "网络工程/优化" },
                ...
                ...
          ],
          industryCnt: 3,
          id: "10501",
          level: 2,
          label: "支撑层",
        },
    .....
    .....
    ]
}

解决办法

进行遍历和递归方式进行替换,初步实现代码如下:

// 自执行函数,进行遍历递归
(function changeKey(_obj){
  for(let key in _obj){
    if(key === 'industryCode'){
      _obj['id'] = _obj[key]
      Reflect.deleteProperty(_obj,'industryCode')
    }
    if(key === 'name'){
      _obj['label'] = _obj[key]
      Reflect.deleteProperty(_obj,'name')
    }
    if(key === 'downstream'){
      _obj['children'] = _obj[key]
      Reflect.deleteProperty(_obj,'downstream')
      if(_obj['children'].length > 0){
        _obj['children'].map(res =>{
          changeKey(res)
        })
      }
    }
  }
})(targetObj)

console.log(targetObj)


/* 
 输出打印结果
   {
    "companyCnt": 2317547,
    "industryCnt": 23,
    "level": 1,
    "id": "105",
    "label": "5G产业",
    "children": [
        {
            "industryCnt": 3,
            "level": 2,
            "children": [
                {
                    "level": 3,
                    "id": "1050101",
                    "label": "网络规划/设计"
                },
                {
                    "level": 3,
                    "id": "1050102",
                    "label": "网络工程/优化"
                }
            ],
            "id": "10501",
            "label": "支撑层"
        },
        {
            "industryCnt": 4,
            "level": 2,
            "children": [
                {
                    "level": 3,
                    "id": "1050201",
                    "label": "芯片"
                },
                {
                    "level": 3,
                    "id": "1050202",
                    "label": "射频器件"
                },
                {
                    "level": 3,
                    "id": "1050203",
                    "label": "关键材料"
                }
            ],
            "id": "10502",
            "label": "基础层"
        },
        {
            "industryCnt": 9,
            "level": 2,
            "children": [
                {
                    "level": 3,
                    "id": "1050301",
                    "label": "主设备"
                },
                {
                    "level": 3,
                    "id": "1050302",
                    "label": "基站天线"
                },
                {
                    "level": 3,
                    "id": "1050303",
                    "label": "SDN/NFV解决方案"
                },
                {
                    "level": 3,
                    "id": "1050304",
                    "label": "光纤光缆"
                },
                {
                    "level": 3,
                    "id": "1050305",
                    "label": "射频滤波器"
                },
                {
                    "level": 3,
                    "id": "1050306",
                    "label": "光模块/光器件"
                },
                {
                    "level": 3,
                    "id": "1050307",
                    "label": "小基站"
                },
                {
                    "level": 3,
                    "id": "1050308",
                    "label": "基站配套"
                }
            ],
            "id": "10503",
            "label": "传输层"
        },
        {
            "industryCnt": 6,
            "level": 2,
            "children": [
                {
                    "level": 3,
                    "id": "1050401",
                    "label": "系统集成"
                },
                {
                    "level": 3,
                    "id": "1050402",
                    "label": "网络优化/维护"
                },
                {
                    "level": 3,
                    "id": "1050403",
                    "label": "运营商"
                },
                {
                    "level": 3,
                    "id": "1050404",
                    "label": "移动终端设备"
                },
                {
                    "level": 3,
                    "id": "1050405",
                    "label": "其他应用层"
                }
            ],
            "id": "10504",
            "label": "应用层"
        }
    ]
}
*/

改进方法

因为每次的要改变的字段要写死在函数里,不适合直接调用,所以需要再次进行封装。

// 需要替换的数据字段
const changeKey = [
    {
        oldKey:'industryCode',
        newKey:'id',
        type:'String', // 替换的值类型
    
    },
     {
        oldKey:'downstream',
        newKey:'children',
        type:'Array', // 替换的值类型
    
    },
     {
        oldKey:'name',
        newKey:'label',
        type:'String', // 替换的值类型
    
    }
]
// 进行遍历递归
function changeKey(_obj,targetKeys){
  targetKeys.map(targetKey =>{
     for(let key in _obj){
      if(key === targetKey.oldKey){
        _obj[targetKey.newKey] = _obj[key]
        Reflect.deleteProperty(_obj, key)
        if(targetKey.type === 'Array' && _obj[targetKey.newKey].length > 0){
          _obj[targetKey.newKey].map(res =>{
              changeKey(res,targetKeys)
          })
        }
      }
     }
  })
}
// 调用
changeKey(targetObj,targetKeys)

小小改进

不难发现,这边最终会把原来的原始数据targetObj进行变更,需要在调整下,使其生成新的对象。

// 需要替换的数据字段
const changeKey = [
    {
        oldKey:'industryCode',
        newKey:'id',
        type:'String', // 替换的值类型
    
    },
     {
        oldKey:'downstream',
        newKey:'children',
        type:'Array', // 替换的值类型
    
    },
     {
        oldKey:'name',
        newKey:'label',
        type:'String', // 替换的值类型
    
    }
]

// 深拷贝&返回
function replaceField(targetObj,targetKeys){
  let _obj = JSON.parse(JSON.stringify(targetObj))
  changeKey(_obj,targetKeys)
  return _obj
}
// 进行遍历递归
function changeKey(_obj,targetKeys){
  targetKeys.map(targetKey =>{
     for(let key in _obj){
      if(key === targetKey.oldKey){
        _obj[targetKey.newKey] = _obj[key]
        Reflect.deleteProperty(_obj, key)
        if(targetKey.type === 'Array' && _obj[targetKey.newKey].length > 0){
          _obj[targetKey.newKey].map(res =>{
              changeKey(res,targetKeys)
          })
        }
      }
     }
  })
}
// 调用
const needObj = replaceField(targetObj,targetKeys)

结尾

当然这绝不是最佳方案,如果有更优雅,更高效的方式,欢迎大神评论~~~