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