You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

方案优势

  1. 一步到位:不需要中间的扁平化和重建步骤,直接递归处理每个节点,逻辑连贯
  2. 代码简洁:所有逻辑集中在一个函数里,去掉了冗余的临时对象和拆分/拼接操作
  3. 性能更优:减少了额外的遍历和字符串操作开销,尤其适合处理大型嵌套对象
  4. 可读性强:每一步都对应需求,容易理解和后续维护

内容的提问来源于stack exchange,提问作者Anji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:47:46