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

搜索并修改深度嵌套的javascript对象,javascript,json,recursion,javascript-objects,traversal,Javascript,Json,Recursion,Javascript Objects,Traversal,我有一个可以与对象、数组、对象数组等深度嵌套的对象 每个嵌套对象都有一个sys属性,该属性又有一个id属性 我有一个单独的id值列表,这些值对应于我要从原始对象中删除的对象。如何递归地遍历整个对象并修改它,使其不再包含这些对象 例如,假设我有以下数据: let data = { sys: { id: '1' }, items: [ { sys: { id: '2' }, fields: { title

我有一个可以与对象、数组、对象数组等深度嵌套的对象

每个嵌套对象都有一个
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);

但是,我不知道如何正确修改数组。此外,我更喜欢创建一个全新的对象,而不是修改现有的对象,以保持不变。

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

  • 要创建新对象,需要在函数中的某个位置使用
    return
  • 要从数组中删除项,您需要首先筛选出有效项,然后递归地调用它们的
    traverse
  • typeof obj[key]==“object”
    即使对于数组也会返回true,所以 下一步
    else if
    块永远不会被命中
  • 至于实现,我的第一步是创建一个helper
    good
    函数来检测无效对象

    good = (obj) =>{
        try{return !(invalidIds.includes(obj.sys.id));}
        catch(err){return true;}
    }
    
    现在主
    遍历
    -

    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;
    };
    
    对于数组对象,根据第2点,我首先过滤掉有效对象,然后将它们映射到遍历。对于对象,
    =
    操作符用于捕获通过递归调用
    遍历
    返回的有效子对象,而不是简单地修改它们


    注意:我几乎不懂javascript,但还是尝试了一下,因为这种递归问题相当常见。所以要注意JS特定的问题。具体来说,如评论中所述,我不满意我如何检查“sys”对象。

    谢谢!在删除
    if(obj.sys==undefined)
    子句后,我使它工作起来,因为这导致许多嵌套对象在完全遍历之前返回。在循环键之前,我还添加了一个
    if(typeof obj==“object”)
    。你的
    typeof
    很有意义。但是你的sys对象是一个特例,那么你是如何处理它的呢?你的
    good()
    函数检查一个对象是否包含一个
    sys.id
    匹配的
    invalidIds
    列表。如果我们从对象的根开始向下遍历,我不认为有任何方法可以到达
    sys
    属性中尚未捕获的点。执行
    if(obj.sys==undefined)if(obj.id!=undefined)
    可以防止它遍历具有任何
    sys.id
    的节点,即使它们有我们需要删除的子节点。对吗?“
    如果
    阻止它遍历具有任何
    sys.id
    的节点,即使它们有我们需要删除的子节点”-不,它们不会被删除,只会删除没有
    sys
    但具有
    id
    的节点。所以是的。如果任何普通节点都有
    id
    ,但没有
    sys
    ,那么它将不会被遍历。但这与你问题的第二行背道而驰。啊,我为困惑道歉,我应该说得更好。基本上每个对象都有一个sys属性,其中包含一个id属性。任何项的id属性都不包含在父sys属性中。我应该说得更清楚些