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

JavaScript如何深度合并两个对象并保留属性层级结构?

问题原因

Object.assign 本身只做第一层属性的浅合并,遇到值是对象、数组这类引用类型的同名属性时,会直接拿后传入对象的属性值整体覆盖前序对象的对应值,不会递归往里合并嵌套的属性,这就是示例里issues字段被整个替换、global属性丢失的原因。

通用实现方案

要实现保留嵌套结构的深度合并,实现思路很直接:递归遍历所有待合并对象的属性,只要同名属性的两侧值都是纯对象,就进入下一层继续合并,而不是直接覆盖整个属性值,适配任意未知属性结构的场景。

无依赖手写实现

以下实现和Object.assign的参数逻辑保持一致,默认会修改第一个传入的目标对象,兼容所有常规JS数据类型场景:

function deepMerge(target, ...sources) {
  // 目标值不是有效对象时初始化为空对象
  if (typeof target !== 'object' || target === null) {
    target = {};
  }

  for (const source of sources) {
    // 跳过null、非对象类型的无效源
    if (typeof source !== 'object' || source === null) continue;

    for (const key of Object.keys(source)) {
      const targetValue = target[key];
      const sourceValue = source[key];

      // 两侧值均为非数组的纯对象时,递归合并内部属性
      if (
        typeof targetValue === 'object' && targetValue !== null &&
        typeof sourceValue === 'object' && sourceValue !== null &&
        !Array.isArray(targetValue) && !Array.isArray(sourceValue)
      ) {
        target[key] = deepMerge(targetValue, sourceValue);
      } else {
        // 基础类型、数组、函数等类型直接覆盖,如有数组合并需求可在此扩展逻辑
        target[key] = sourceValue;
      }
    }
  }
  return target;
}

使用示例

const object1 = { issues: { global: 'a great string!' } };
const object2 = { issues: { cooldown: 'oh well, another message!' } };

deepMerge(object1, object2);
console.log(object1);
// 输出结果符合预期:{ issues: { global: 'a great string!', cooldown: 'oh well, another message!' } }

使用注意

  • 如果不希望修改原对象,调用时将第一个参数传入空对象即可:const mergedResult = deepMerge({}, object1, object2),原对象不会被改动。
  • 上述实现默认遇到数组时直接用源数组覆盖目标值,如果业务需要数组合并(比如拼接、按唯一ID去重合并数组项),可以在对应判断分支中自行扩展逻辑。
  • 不要用JSON.parse(JSON.stringify())配合对象展开运算符实现合并,这种方案会丢失函数、undefined、Symbol类型的属性,还会错误转换日期、正则等特殊对象,仅适合纯JSON数据场景,通用性极差。

工具库方案

如果项目中已经引入了Lodash等通用工具库,可以直接使用库内置的_.merge方法,该方法已经处理了所有边界场景,逻辑和上述手写实现一致,可直接调用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 06:18:09