不能。object.assign只做浅拷贝,嵌套对象会被整体替换而非递归合并;常见错误包括误用多层assign、忽略null/undefined源对象、错误假设支持deep参数;手动实现需判断纯对象类型并递归,同时处理函数、正则等原子值直接覆盖。

Object.assign 能不能直接做深度合并
不能。Object.assign 只做浅拷贝,遇到嵌套对象时,会直接替换整个子对象,而不是递归合并属性。比如:target.a.b = 1 和 source.a.c = 2 合并后,target.a 会变成 source.a 的完整副本,target.a.b 就丢了。
用 Object.assign 模拟深度覆盖的常见错误写法
有人试图连写多次 Object.assign 来“分层覆盖”,比如先合并顶层,再手动处理 a 层——这容易漏字段、逻辑错乱,且无法处理动态嵌套层级。更典型的问题是:把 Object.assign({}, a, b) 当成安全合并,却没意识到 b.a 是对象时,它会完全取代 a.a,而非融合。
- 错误示例:
Object.assign({a: {x: 1}}, {a: {y: 2}})→ 结果是{a: {y: 2}},x消失了 - 错误假设:
Object.assign支持deep: true参数(它根本不支持) - 忽略
null或undefined源对象导致报错,需提前过滤
手动实现轻量级深度覆盖(基于 Object.assign 思路)
核心是:对每个 key,判断值是否为纯对象,是则递归调用合并函数;否则直接用 Object.assign 覆盖。不依赖第三方库,适合组件默认配置 + 用户配置的简单场景。
function deepAssign(target, ...sources) {
sources.forEach(source => {
if (source == null) return;
Object.keys(source).forEach(key => {
const targetVal = target[key];
const sourceVal = source[key];
if (
sourceVal !== null &&
typeof sourceVal === 'object' &&
!Array.isArray(sourceVal) &&
targetVal !== null &&
typeof targetVal === 'object' &&
!Array.isArray(targetVal)
) {
deepAssign(targetVal, sourceVal);
} else {
target[key] = sourceVal;
}
});
});
return target;
}
使用示例:deepAssign({a: {x: 1, z: 9}}, {a: {y: 2}, b: 3}) → {a: {x: 1, y: 2, z: 9}, b: 3}
组件配置合并时必须考虑的边界情况
真实组件配置常含函数、正则、Date 等非纯对象类型,它们不该被“深度合并”,而应直接覆盖。同时要避免修改原始配置对象。
- 始终用空对象作为第一参数:
deepAssign({}, defaultConfig, userConfig),防止污染默认配置 - 遇到
Function、Date、RegExp、Map、Set时,跳过递归,直接赋值(即当作原子值处理) - 数组建议整体替换(而非按索引合并),除非业务明确需要 concat 或 merge-by-id
- 如果用户传了
undefined字段,它会覆盖默认值——这点和 Vue/React 的 props 合并逻辑一致,但需文档说明
深度合并不是银弹,嵌套过深或结构动态变化时,不如用 structuredClone + 显式遍历,或改用 JSON Schema 驱动的合并策略。










