JavaScript中嵌套对象键过滤(仅留含value节点)的优化方案问询
问题:简化JSON对象的清理与转换逻辑
我有如下JSON对象:
x = { "prop1": { "description": "prop1", "dataType": "string", "value" : "abc" }, "prop2": { "sub1": { "description": "sub1", "dataType": "integer", "value" : 12 }, "sub2": { "description": "sub2", "dataType": "integer" } }, "prop3": { "input": { "name": { "description": "input messages", "dataType": "boolean", "value": false } }, "output": { "description": "output messages", "dataType": "boolean", "value": false } } }我需要移除该对象中的
description、dataType键,同时移除不含value键的节点,预期输出如下:y = { "prop1": { "value" : "abc" }, "prop2": { "sub1": { "value" : 12 } }, "prop3": { "input": { "name": { "value": false } }, "output": { "value": false } } }我当前的解决方案如下:
function findValue(obj, string, obj1) { if (obj.hasOwnProperty("value")) { obj1[string.substring(1)] = obj.value return } for (var key in obj) { findValue(obj[key], [string, key].join("."), obj1) } } console.log(x); var x1 = {} findValue(x, "", x1) var y = {}; function assign(obj, keyPath, value) { const lastKeyIndex = keyPath.length - 1; for (var i = 0; i < lastKeyIndex; ++i) { const key = keyPath[i]; if (!(key in obj)) { obj[key] = {} } obj = obj[key]; } obj[keyPath[lastKeyIndex]] = { "value": value }; } Object.keys(x1).forEach(key => { const keyPath = key.split('.'); let value = x1[key]; if (value != null) { this.assign(y, keyPath, value); } }); console.log(y);我的实现方式较为繁琐,先将对象转换为父键子键组合的格式,再转换为预期格式。是否有更优的实现方式?
更优的实现方案:递归直接处理对象
你的思路是先扁平化再重建,确实绕了一圈。其实我们可以用递归遍历+原地过滤的方式一步到位,代码更简洁,逻辑也更直观。
核心思路
- 遍历每个对象的键值对,直接跳过
description和dataType这两个不需要的键 - 如果当前值是对象,递归处理这个子对象,得到清理后的结果
- 只有当子对象处理后不为空(包含有效节点),才把它保留到最终结果里
- 一旦发现当前对象包含
value键,直接返回仅包含value的结构,不用再处理其他键
代码实现
function cleanObject(obj) { // 兜底处理:非对象直接返回 if (typeof obj !== 'object' || obj === null) { return obj; } const cleaned = {}; for (const key in obj) { // 跳过不需要的键 if (key === 'description' || key === 'dataType') { continue; } const value = obj[key]; // 递归处理子对象 const processedValue = cleanObject(value); // 如果当前节点本身就有value,直接保留这个结构并返回 if (obj.hasOwnProperty('value')) { return { value: obj.value }; } // 只有处理后的子对象有内容,才添加到结果中 if (processedValue && Object.keys(processedValue).length > 0) { cleaned[key] = processedValue; } } // 检查当前对象是否直接包含value(比如prop3的output节点) if (obj.hasOwnProperty('value')) { return { value: obj.value }; } // 空对象返回null,避免保留无意义的空节点 return Object.keys(cleaned).length > 0 ? cleaned : null; } // 测试使用 const y = cleanObject(x); console.log(y);
方案优势
- 一步到位:不需要中间的扁平化和重建步骤,直接递归处理每个节点,逻辑连贯
- 代码简洁:所有逻辑集中在一个函数里,去掉了冗余的临时对象和拆分/拼接操作
- 性能更优:减少了额外的遍历和字符串操作开销,尤其适合处理大型嵌套对象
- 可读性强:每一步都对应需求,容易理解和后续维护
内容的提问来源于stack exchange,提问作者Anji
相关产品推荐
相关产品推荐

