Javascript 递归过滤/减少嵌套对象

Javascript 递归过滤/减少嵌套对象,javascript,arrays,object,recursion,filter,Javascript,Arrays,Object,Recursion,Filter,我有一个嵌套很深的对象,我需要搜索它来删除某些键。要删除的密钥存储在removeKeys数组中指示的数组中。 目前,该函数仅过滤顶级对象,但对其余对象进行精细缩放,它只是不过滤子对象。如何正确减少完整对象以获得所需的输出 初始未过滤对象: let item = { "label": "test", "id": "test", "styles": { "label": "Styles",

我有一个嵌套很深的对象,我需要搜索它来删除某些键。要删除的密钥存储在removeKeys数组中指示的数组中。 目前,该函数仅过滤顶级对象,但对其余对象进行精细缩放,它只是不过滤子对象。如何正确减少完整对象以获得所需的输出

初始未过滤对象:

let item = {
            "label": "test",
            "id": "test",
            "styles": {
                "label": "Styles",
                "styles": {
                    "test": {
                        "test": "test",
                        "label": "test",
                        "test1": {
                            "label": "test",
                            "image": {
                                "label": "test",
                                "type": "test",
                                "value": "test",
                                "autoSelect": "",
                                "id": ""
                            }
                        }
                    }
                }
            },
            "test": {
                "label": "test",
                "test": []
            }
        }
要从对象中删除的关键帧:

const removeKeys = ["label", "type", "autoSelect"];
用于筛选嵌套对象的递归函数:

let filterObject = filterNestObject(item);

function filterNestObject(item) {
  return Object.keys(item)
  .filter(key => {
    if (typeof item[key] === 'object') filterNestObject(item[key]);

    if (!removeKeys.includes(key)) return true;

    return false 
  })  
  .reduce((object, key) => {
    return {
      ...object,
      [key]: item[key]
    };
  }, {});

}
预期结果将是:

{
            "id": "test",
            "styles": {
                "styles": {
                    "test": {
                        "test": "test",
                        "test1": {
                            "image": {
                                "value": "test",
                                "id": ""
                            }
                        }
                    }
                }
            },
            "test": {
                "test": []
            }
        }

它有点粗糙,性能也不是很好,因此如果您处理非常大的对象图,它可能不是一个好的解决方案,但这里有一个使用replacer回调的单行解决方案:

演示:

让观众={ 标签:测试, id:测试, 风格:{ 标签:样式, 风格:{ 测试:{ 测试:测试, 标签:测试, 测试1:{ 标签:测试, 图片:{ 标签:测试, 类型:测试, 值:测试, 自动选择:, 身份证件: } } } } }, 测试:{ 标签:测试, 测试:[] } } 常量removeKeys=[标签、类型、自动选择]; 让newAudience=JSON.parseJSON.stringifyaudience,k,v=>removeKeys.includex?未定义:v;
console.lognewviewer 它有点粗糙,性能也不是很好,因此如果您处理非常大的对象图,它可能不是一个好的解决方案,但这里有一个使用replacer回调的单行解决方案:

演示:

让观众={ 标签:测试, id:测试, 风格:{ 标签:样式, 风格:{ 测试:{ 测试:测试, 标签:测试, 测试1:{ 标签:测试, 图片:{ 标签:测试, 类型:测试, 值:测试, 自动选择:, 身份证件: } } } } }, 测试:{ 标签:测试, 测试:[] } } 常量removeKeys=[标签、类型、自动选择]; 让newAudience=JSON.parseJSON.stringifyaudience,k,v=>removeKeys.includex?未定义:v;
console.lognewviewer 您以递归方式调用函数,但不会对该递归调用返回的结果执行任何操作。您必须使用过滤后的值覆盖子项:

让项目={ 标签:测试, id:测试, 风格:{ 标签:样式, 风格:{ 测试:{ 测试:测试, 标签:测试, 测试1:{ 标签:测试, 图片:{ 标签:测试, 类型:测试, 值:测试, 自动选择:, 身份证件: } } } } }, 测试:{ 标签:测试, 测试:[] } } 常量removeKeys=[标签、类型、自动选择]; 设filterObject=FilternStobjectItem; 函数过滤器目标项{ 返回Object.KeyItem .filterkey=>{ 如果项的类型[键]=“对象”{ //将键设置为递归调用函数返回的筛选结果 项[键]=过滤器对象项[键]; } if!removeKeys.includeKey返回true; 返回错误 } .reduceobject,键=>{ 返回{ 对象 [键]:项[键] }; }, {}; }
console.LogFilternStobjectItem 您以递归方式调用函数,但不会对该递归调用返回的结果执行任何操作。您必须使用过滤后的值覆盖子项:

让项目={ 标签:测试, id:测试, 风格:{ 标签:样式, 风格:{ 测试:{ 测试:测试, 标签:测试, 测试1:{ 标签:测试, 图片:{ 标签:测试, 类型:测试, 值:测试, 自动选择:, 身份证件: } } } } }, 测试:{ 标签:测试, 测试:[] } } 常量removeKeys=[标签、类型、自动选择]; 设filterObject=FilternStobjectItem; 函数过滤器目标项{ 返回Object.KeyItem .filterkey=>{ 如果项的类型[键]=“对象”{ //将键设置为递归调用函数返回的筛选结果 项[键]=过滤器对象项[键]; } if!removeKeys.includeKey返回true; 返回错误 } .reduceobject,键=>{ 返回{ 对象 [键]:项[键] }; }, {}; }
console.LogFilternStobjectItem 代码中的错误是在过滤器回调中执行递归调用。但是在这里,您将丢失递归调用返回的对象。而是在reduce回调中进行

一个小的修正:为了测试一个值是否是一个对象,仅仅做typeof item[key]==object是不够的,因为null也会通过该测试。以下是修改后的代码:

函数过滤器目标项{ 返回Object.KeyItem .filterkey=>!removeKeys.IncludeKey .reduceAC,键=>{ 返回Object.assignacc{ [键]:Objectitem[键]==项[键]?过滤器目标项[键]:项[键] }; },Array.isArrayitem?[] : {}; } const item={label:test,id:test,style:{label:style,style:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:},test:{label:test,test:[]}; 常量removeKeys=[标签、类型、自动选择]; 常量filterObject=FilternStobjectItem;
console.logfilterObject 代码中的错误是在过滤器回调中执行递归调用。但是在这里,您将丢失递归调用返回的对象。而是在reduce回调中进行

一个小的修正:为了测试一个值是否是一个对象,仅仅做typeof item[key]==object是不够的,因为null也会通过该测试。以下是修改后的代码:

函数过滤器目标项{ 返回Object.KeyItem .filterkey=>!removeKeys.IncludeKey .reduceAC,键=>{ 返回Object.assignacc{ [键]:Objectitem[键]==项[键]?过滤器目标项[键]:项[键] }; },Array.isArrayitem?[]:{}; } const item={label:test,id:test,style:{label:style,style:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:},test:{label:test,test:[]}; 常量removeKeys=[标签、类型、自动选择]; 常量filterObject=FilternStobjectItem;
console.logfilterObject 您可以通过采用迭代和递归方法来过滤键并构建新对象

函数removeobject、键{ 返回Object.assign{},…Object.keysobject .filterk=>!keys.includesk .mapk=>{[k]:对象[k]&&typeof对象[k]=='object'?移除对象[k],键:对象[k]} ; } var item={label:test,id:test,style:{label:style,style:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:}}},test:{label:test,test:[]}, removeKeys=[标签、类型、自动选择]; console.logremovietem,removeKeys;
.作为控制台包装器{max height:100%!important;top:0;}您可以通过采用迭代和递归方法筛选键并构建新对象

函数removeobject、键{ 返回Object.assign{},…Object.keysobject .filterk=>!keys.includesk .mapk=>{[k]:对象[k]&&typeof对象[k]=='object'?移除对象[k],键:对象[k]} ; } var item={label:test,id:test,style:{label:style,style:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:}}},test:{label:test,test:[]}, removeKeys=[标签、类型、自动选择]; console.logremovietem,removeKeys; .作为控制台包装{max height:100%!important;top:0;}我可能会使用Object.entries、filter+includes、map和Object.fromEntries-

在你的物品上试一试-

输出-

{
  "id": "test",
  "styles": {
    "styles": {
      "test": {
        "test": "test",
        "test1": {
          "image": {
            "value": "test",
            "id": ""
          }
        }
      }
    }
  },
  "test": {
    "test": {}
  }
}
编辑以支持阵列-

const removeDeepKeys = (keys = [], o = {}) =>
  Array .isArray (o)
    ? o .map (v => removeKeys (keys, v))
    : Object (o) === o
        ? Object
            .fromEntries
              ( Object
                  .entries (o)
                  .filter (([ k, _ ]) => ! keys .includes (k))
                  .map (([ k, v ]) => [ k, removeDeepKeys (keys, v) ])
              )
        : o
我可能会使用Object.entries、filter+includes、map和Object.fromEntries-

在你的物品上试一试-

输出-

{
  "id": "test",
  "styles": {
    "styles": {
      "test": {
        "test": "test",
        "test1": {
          "image": {
            "value": "test",
            "id": ""
          }
        }
      }
    }
  },
  "test": {
    "test": {}
  }
}
编辑以支持阵列-

const removeDeepKeys = (keys = [], o = {}) =>
  Array .isArray (o)
    ? o .map (v => removeKeys (keys, v))
    : Object (o) === o
        ? Object
            .fromEntries
              ( Object
                  .entries (o)
                  .filter (([ k, _ ]) => ! keys .includes (k))
                  .map (([ k, v ]) => [ k, removeDeepKeys (keys, v) ])
              )
        : o

不久前,我尝试创建一个cloneObj方法来使用新方案深度克隆一个对象。你可以在下一个链接中查看我当时提出的问题,以供参考:

我相信这种方法可以稍加修改,以适应您的目标:

const item={label:test,id:test,styles:{label:style,styles:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:}},test:{label:test,test:[{label:foo,test:test:test4}}}; 常量removeKeys=[标签、类型、自动选择]; const cloneObjWithoutKeys=obj,keys=> { 如果Objectobj!==obj 返回obj; 如果Array.isArrayobj 返回obj.mapo=>cloneObjWithoutKeyso,keys; 返回Object.fromEntries Object.entriesobj .filter[k,v]=>!keys.includesk .map[k,v]=>[k,cloneobj不带键v,键] ; } console.logcloneobj不带按键项,移除按键; .as控制台{背景颜色:黑色!重要;颜色:石灰;}
.as console wrapper{max height:100%!important;top:0;}不久前,我尝试创建一个cloneObj方法,以使用新方案深度克隆对象。你可以在下一个链接中查看我当时提出的问题,以供参考:

我相信这种方法可以稍加修改,以适应您的目标:

const item={label:test,id:test,styles:{label:style,styles:{test:{test:test,label:test,test1:{label:test,image:{label:test,type:test,value:test,autoSelect:,id:}},test:{label:test,test:[{label:foo,test:test:test4}}}; 常量removeKeys=[标签、类型、自动选择]; const cloneObjWithoutKeys=obj,keys=> { 如果Objectobj!==obj 返回obj; 如果Array.isArrayobj 返回obj.mapo=>cloneObjWithoutKeyso,keys; 返回Object.fromEntries Object.entriesobj .filter[k,v]=>!钥匙,桌子 .map[k,v]=>[k,cloneobj不带键v,键] ; } console.logcloneobj不带按键项,移除按键; .as控制台{背景颜色:黑色!重要;颜色:石灰;}
.作为控制台包装器{max height:100%!important;top:0;}这里的缺点是它只适用于简单的数据类型。只要输入数据具有Set、Map、Date、RegExp等值。。。等等,它将不起作用。@trincot正确,这仅适用于可序列化到JSON或从JSON序列化的值。正如我所说,这是一种黑客行为,并不是适用于所有场景的正确解决方案。对于具有严格数据类型的对象的正确场景来说非常有趣。这里的缺点是它只适用于简单的数据类型。只要输入数据具有Set、Map、Date、RegExp等值。。。等等,它将不起作用。@trincot正确,这仅适用于可序列化到JSON或从JSON序列化的值。正如我所说,这是一种黑客行为,并不是所有场景的正确解决方案。对于具有严格数据类型的对象的正确场景非常有趣。这是唯一没有将数组转换为对象的解决方案。感谢您采用edge的情况。谢谢,但您应该注意,Object.fromEntries目前不受很好的支持。这是唯一没有将数组转换为对象的解决方案。感谢您使用edge案例。谢谢,但您应该注意,Object.fromEntries目前不太受支持。
const removeDeepKeys = (keys = [], o = {}) =>
  Array .isArray (o)
    ? o .map (v => removeKeys (keys, v))
    : Object (o) === o
        ? Object
            .fromEntries
              ( Object
                  .entries (o)
                  .filter (([ k, _ ]) => ! keys .includes (k))
                  .map (([ k, v ]) => [ k, removeDeepKeys (keys, v) ])
              )
        : o