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

递归Object.assign未按预期工作,请求排查问题原因

递归调用Object.assign的常见问题解析

嘿,我来帮你揪揪递归用Object.assign时容易踩的那些坑!其实核心问题大多围绕Object.assign本身的特性,加上递归逻辑没考虑周全导致的:

1. 没意识到Object.assign是浅拷贝

这是最常见的问题!Object.assign只会复制对象的第一层属性,如果遇到嵌套的对象,它只会把内层对象的引用赋值过去,而不是深层复制。比如你递归合并两个带嵌套的对象时:

const obj1 = { a: { b: 1 } };
const obj2 = { a: { c: 2 } };

// 错误的递归合并(只是每层用Object.assign)
function badDeepAssign(target, source) {
  return Object.assign(target, source);
}
// 递归调用后,obj1.a会直接被obj2.a覆盖,结果是{a: {c:2}},而不是预期的{a: {b:1,c:2}}

因为递归到内层对象时,直接用Object.assign会把新的内层对象引用覆盖旧的,而不是合并它们的属性。

2. 递归终止条件没处理边界情况

很多人写递归时,没判断当前值是不是真正的可遍历对象,比如忽略了null(typeof null === 'object')、原始类型(字符串、数字等),或者数组的特殊情况:

  • 如果递归到null,用Object.assign会报错;
  • 如果遇到数组,Object.assign会把数组当成对象按索引合并,比如Object.assign([1,2], [3])会得到[3,2],这显然不符合大多数人数组合并的预期。

3. 错误地复用Object.assign的合并逻辑到深层

Object.assign的合并规则是“后面的源对象覆盖前面的”,但递归到深层时,你可能想要的是合并属性而不是覆盖整个对象,这时候直接套Object.assign就会和预期相悖。


给你一个修正后的递归合并示例

如果你的需求是深合并对象(包括处理嵌套对象和数组),可以这么写:

function deepMerge(target, ...sources) {
  // 遍历所有源对象
  for (const source of sources) {
    // 遍历源对象的每个键
    for (const key in source) {
      const sourceValue = source[key];
      // 处理嵌套对象(排除数组)
      if (sourceValue && typeof sourceValue === 'object' && !Array.isArray(sourceValue)) {
        // 如果目标对象没有这个键,先初始化空对象
        if (!target[key]) target[key] = {};
        // 递归合并深层对象
        deepMerge(target[key], sourceValue);
      } else if (Array.isArray(sourceValue)) {
        // 数组单独处理:这里用浅合并,把源数组元素追加到目标数组后
        target[key] = [...(target[key] || []), ...sourceValue];
      } else {
        // 原始类型直接赋值(覆盖)
        target[key] = sourceValue;
      }
    }
  }
  return target;
}

这个函数会:

  • 对嵌套对象递归合并属性,而不是直接覆盖;
  • 单独处理数组,避免Object.assign的索引合并问题;
  • 处理null和原始类型的边界情况。

如果只是需要深拷贝而不是合并,现在浏览器和Node.js已经支持原生的structuredClone() API,用它更省心哦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:49:50