如何从嵌套对象中根据属性移除指定元素(含子元素)
嵌套对象树移除指定type节点的问题解决
需求
从嵌套对象树中移除所有type属性为'green'的对象,若该对象包含children子元素则一并移除。
示例对象
const obj = { id: '01', children: [ { id: '02', type: 'green', children: [ { id: '03', type: 'black', children: [], }, { id: '04', type: 'green', children: [ { id: '05', type: 'white', children: [], } ], } ], }, { id: '06', type: 'black', children: [ { id: '07', type: 'green', children: [], }, { id: '08', type: 'white', children: [ { id: '09', type: 'green', children: [], } ], } ], }, ] }
预期结果
移除type为"green"的对象后:
const expectedObj = { id: '01', type: 'orange', children: [ { id: '06', type: 'black', children: [ { id: '08', type: 'white', children: [], } ], }, ] }
尝试的代码及问题
尝试的代码:
let match = false const removeByType = (data, type) => { match = data.some(d => d.type == type) if (match) { data = data.filter(d => d.type !== type) } else { data.forEach(d => { d.children = removeByType(d.children, type) }) } return data } let data = obj.children console.dir(removeByType(data, 'black'), { depth: null })
执行后发现{ id: '03', type: 'black', children: [] }仍存在于对象树中,不符合预期。
问题分析
原代码的核心问题:
- 全局变量
match在递归过程中会被覆盖,导致逻辑判断混乱; - 逻辑分支完全错误:只要当前数组有匹配节点就直接过滤,但过滤后剩余节点的子节点没继续处理;只有数组完全无匹配节点时才处理子节点,逻辑倒置;
- 调用时传入的目标类型是
'black',和需求的'green'不符。
正确解法
我们需要递归遍历每一层节点,先过滤当前层级的目标节点,再处理剩余节点的子元素:
const removeByType = (node, targetType) => { // 处理数组类型的节点集合 if (Array.isArray(node)) { return node .filter(item => item.type !== targetType) .map(item => ({ ...item, children: removeByType(item.children || [], targetType) })); } // 处理单个对象节点 if (node.type === targetType) { return null; } return { ...node, children: removeByType(node.children || [], targetType) }; }; // 处理根对象并输出结果 const result = removeByType(obj, 'green'); console.dir(result, { depth: null });
代码说明
- 区分数组和单个对象两种场景,分别处理;
- 先过滤当前层级的目标节点,再递归处理剩余节点的子元素,确保所有嵌套层级的目标节点都被移除;
- 采用纯函数方式,不修改原对象,返回全新的对象树;
- 调用时传入正确的目标类型
'green'。
执行这段代码后,所有type为'green'的节点(包括其下所有子节点)都会被移除,得到符合预期的结果。
内容的提问来源于stack exchange,提问作者track_p54skate
相关产品推荐
相关产品推荐

