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

递归嵌套对象差异对比函数未返回空对象的修复咨询

修复嵌套对象对比时返回空对象的问题

你的代码存在几个关键问题,导致嵌套对比后出现冗余的空对象结构,以下是问题分析和修复方案:

原代码核心问题

  • 笔误:函数参数定义的是baseObj,但判断逻辑里误用了未定义的refObj;递归调用时写了extractValueChanges,但实际函数名是extractChanges。
  • 循环提前返回:遇到第一个非标量类型且值不同的字段就直接return,会中断后续所有字段的处理。
  • 递归结果未过滤:当嵌套对象对比后无差异(返回空对象)时,依然将这个空对象键值对加入结果,导致出现{address: {coordinates:{}}}这类冗余结构。

修复后的完整代码

function isEmptyValue(value: any): boolean {
  // 同时处理空对象、空数组的判断
  if (Array.isArray(value)) return value.length === 0;
  if (typeof value === 'object' && value !== null) return Object.keys(value).length === 0;
  return false;
}

function extractChanges(
  baseObj: Record<string, any>,
  newObj: Record<string, any>
): Record<string, any> {
  const result: Record<string, any> = {};

  // 处理边界情况
  if (isEmptyValue(baseObj) && isEmptyValue(newObj)) return result;
  if (isEmptyValue(baseObj)) return {...newObj};
  if (isEmptyValue(newObj)) return result;

  // 合并两个对象的所有键,避免遗漏baseObj有但newObj删除的字段
  const allKeys = new Set([...Object.keys(baseObj), ...Object.keys(newObj)]);

  for (const key of allKeys) {
    const baseValue = baseObj[key];
    const newValue = newObj[key];

    // 判断是否为引用类型(数组/对象)
    const isBaseRefType = typeof baseValue === 'object' && baseValue !== null;
    const isNewRefType = typeof newValue === 'object' && newValue !== null;

    if (isBaseRefType && isNewRefType) {
      // 递归对比嵌套结构
      const nestedChanges = extractChanges(baseValue, newValue);
      // 仅当递归结果非空时,才加入最终结果
      if (!isEmptyValue(nestedChanges)) {
        result[key] = nestedChanges;
      }
    } else if (newValue !== baseValue) {
      // 非引用类型,值不同则记录差异
      result[key] = newValue;
    }
  }

  return result;
}

关键修改说明

  1. 修正笔误:统一将refObj替换为baseObj,递归调用改为正确的extractChanges。
  2. 完善空值判断:新增isEmptyValue函数,同时识别空对象和空数组,避免逻辑误判。
  3. 合并所有键:用Set获取两个对象的全部键,确保不会遗漏baseObj存在但newObj删除的字段(可根据需求调整删除字段的处理逻辑)。
  4. 过滤空递归结果:嵌套对比后若返回空值(无差异),则不将该键加入最终结果,彻底解决冗余空对象问题。
  5. 移除提前return:循环中不再提前返回,保证所有字段都能被完整处理。

测试验证

对比相同对象时,返回空对象:

const obj = {
  id: 1,
  name: 'test',
  address: {
    country: 'XXX',
    state: 'XXXX',
    coordinates: {
      longitude: 'xxxx',
      latitude: 'xxxx',
    },
  },
};

console.log(extractChanges(obj, obj)); // 输出:{}

对比有差异的嵌套对象时,仅返回实际差异:

const modifiedObj = {
  ...obj,
  address: {
    ...obj.address,
    coordinates: {
      ...obj.address.coordinates,
      longitude: 'yyyy',
    },
  },
};

console.log(extractChanges(obj, modifiedObj)); 
// 输出:{ address: { coordinates: { longitude: 'yyyy' } } }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 13:15:19