递归过滤/减少嵌套对象
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归过滤/减少嵌套对象相关的知识,希望对你有一定的参考价值。
我有一个深层嵌套的对象,我需要搜索删除某些键。要删除的键存储在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": []
前段时间,我尝试使用新提议cloneObj()
创建一个Object.fromEntries()方法来深度克隆对象。您可以在下一个链接上查看我在那个时刻提出的问题以供参考:Deep-Cloning an object using Object.fromEntries()
我相信这种方法可以稍加修改,以满足您的目标:
const 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": [label: "foo", test: "test4"];
const removeKeys = ["label", "type", "autoSelect"];
const cloneObjWithoutKeys = (obj, keys) =>
if (Object(obj) !== obj)
return obj;
else if (Array.isArray(obj))
return obj.map(o => cloneObjWithoutKeys(o, keys));
return Object.fromEntries(
Object.entries(obj)
.filter(([k, v]) => !keys.includes(k))
.map(([k, v]) => ([k, cloneObjWithoutKeys(v, keys)])
));
console.log(cloneObjWithoutKeys(item, removeKeys));
.as-console background-color:black !important; color:lime;
.as-console-wrapper max-height:100% !important; top:0;
它有点hacky并且性能不高,所以如果你处理的是非常大的对象图,它可能不是一个好的解决方案,但这里是使用replacer
中的JSON.stringify
回调的单线解决方案:
JSON.parse(JSON.stringify(audience, (k, v) => removeKeys.includes(k) ? undefined : v));
演示:
let audience =
"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 newAudience = JSON.parse(JSON.stringify(audience, (k, v) => removeKeys.includes(k) ? undefined : v));
console.log(newAudience);
您可以通过采用迭代和递归方法过滤键并构建新对象。
function remove(object, keys)
return Object.assign(, ...Object.keys(object)
.filter(k => !keys.includes(k))
.map(k => ( [k]: object[k] && typeof object[k] === 'object' ? remove(object[k], keys) : object[k] ))
);
var 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: [] ,
removeKeys = ["label", "type", "autoSelect"];
console.log(remove(item, removeKeys));
.as-console-wrapper max-height: 100% !important; top: 0;
您的代码中的错误是您在filter
回调中执行递归调用。但是你丢失了递归调用返回的对象。而是在reduce
回调中进行。
一个小的修正:为了测试一个值是否是一个对象,它不足以做typeof item[key] === "object"
,因为null
也会通过该测试。这是改编的代码:
function filterNestObject(item)
return Object.keys(item)
.filter(key => !removeKeys.includes(key))
.reduce((acc, key) =>
return Object.assign(acc,
[key]: Object(item[key]) === item[key] ? filterNestObject(item[key]) : item[key]
);
, Array.isArray(item) ? [] : );
const 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"];
const filterObject = filterNestObject(item);
console.log(filterObject);
你以递归方式调用函数,但是你没有对这个递归调用返回的结果做任何事情。您必须使用筛选值覆盖子键:
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')
// set the key to the filtered result returned by the recursively called function
item[key] = filterNestObject(item[key]);
if (!removeKeys.includes(key)) return true;
return false
)
.reduce((object, key) =>
return
...object,
[key]: item[key]
;
, );
console.log(filterNestObject(item));
我可能会使用Object.entries
,filter
+ includes
,map
和Object.fromEntries
-
const removeDeepKeys = (keys = [], o = ) =>
Object (o) === o
? Object
.fromEntries
( Object
.entries (o)
.filter (([ k, _ ]) => ! keys .includes (k))
.map (([ k, v ]) => [ k, removeDeepKeys (keys, v) ])
)
: o
试试你的item
-
removeDeepKeys ([ 'label', 'type', 'autoSelect' ], item)
输出 -
"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
以上是关于递归过滤/减少嵌套对象的主要内容,如果未能解决你的问题,请参考以下文章