搜索并修改深层嵌套的javascript对象

时间:2017-11-01 11:18:31

标签: javascript json recursion javascript-objects traversal

我有一个可以与对象,数组,对象数组等深层嵌套的对象。

每个嵌套对象都有一个sys属性,而该属性又具有id属性。

我有一个单独的id值列表,这些值对应于我想从原始对象中删除的对象。我怎样才能递归遍历整个对象并将其修改为不再包含这些?

例如,假设我有以下数据:

let data = {
  sys: {
    id: '1'
  },
  items: [
    {
      sys: {
        id: '2'
      },
      fields: {
        title: 'Item title',
        sponsor: {
          sys: {
            id: '3'
          },
          fields: {
            title: 'Sponsor Title'
          }
        },
        actions: [
          {
            sys: {
              id: '4'
            },
            fields: {
              title: 'Google',
              url: 'google.com'
            }
          },
          {
            sys: {
              id: '5'
            },
            fields: {
              title: 'Yahoo',
              url: 'yahoo.com'
            }
          }
        ]
      }
    }
  ]
}

然后我有一个id的数组要删除:

const invalidIds = ['3', '5'];

运行该函数后,生成的对象应该将sys.id '3'设置为null的属性和sys.id '5'的对象设置为// Desired Output: { sys: { id: '1' }, items: [ { sys: { id: '2' }, fields: { title: 'Item title', sponsor: null, actions: [ { sys: { id: '4' }, fields: { title: 'Google', url: 'google.com' } } ] } } ] } 应该简单地从其包含的数组中删除:

const process = (key, value) => {
  if (typeof value === 'object' && value.sys && value.sys.id && invalidIds.includes(value.sys.id)) {
    console.log('found one', value.sys.id);
  }
};

const traverse = (obj, func) => {
  for (let key in obj) {
    func.apply(this, [key, obj[key]]);

    if (obj[key] !== null) {
      if (typeof obj[key] === 'object') {
        traverse(obj[key], func);
      } else if (obj[key].constructor === Array) {
        obj[key].map(item => {
          if (typeof item === 'object') {
            traverse(item, func);
          }
        });
      }
    }
  }
};

traverse(data, process);

this solution的帮助下,我能够递归搜索对象及其各种嵌套数组:

header('Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept');

但是我无法弄清楚如何正确修改数组。另外,我更喜欢创建一个全新的对象,而不是修改现有的对象以保持不变。

1 个答案:

答案 0 :(得分:1)

以下是导致我的解决方案的观察结果:

  1. 要创建新对象,您需要在函数中的某处使用return
  2. 要从数组中删除项目,您需要先过滤掉有效项目,然后递归调用它们上的traverse
  3. typeof obj[key] === 'object'即使对于Array也会返回true,所以 下一个else if块不会被击中。
  4. 至于实现,我的第一步是创建一个帮助器good函数来检测无效对象。

    good = (obj) =>{
        try{return !(invalidIds.includes(obj.sys.id));}
        catch(err){return true;}
    }
    

    现在是主traverse -

    traverse = (obj) => {
        //I assumed when an object doesn't have 'sys' but have 'id', it must be sys obj.
        if (obj==null) return null;
        if(obj.constructor === Array) return obj.filter(good).map(traverse);
        if(obj.sys==undefined) { //this checks if it's sys object.
            if(obj.id!=undefined) return obj;  
        }
    
        for (let key in obj) {
            if (key!=0) {
                if (good(obj[key])) {obj[key] = traverse(obj[key]);}
                else {obj[key] = null;}
            }
        }
            return obj;
    };
    

    对于Array对象,根据第2点,我首先筛选出有效对象,然后将它们映射到遍历。对于Objects,=运算符用于捕获有效的子对象,通过递归调用traverse返回,而不是简单地修改它们。

    注意:我几乎不知道javascript,但无论如何都要接受它,因为这个递归问题相当普遍。所以要注意JS的具体问题。具体来说,正如评论中所述,我不满足于如何检查'sys'对象。