递归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
相关产品推荐
相关产品推荐

