在 Vue 中,当直接使用 Object.assign()
或展开运算符 {...}
合并对象时,可能遇到 目标对象引用被保留但部分属性未被覆盖 的问题。这是因为这些方法执行的是浅合并(Shallow Merge),当遇到嵌套对象时,子对象的引用会被保留而非递归合并。以下是解决方案:
问题复现
data() {
return {
originalObj: {
a: 1,
nested: { b: 2, c: 3 } // 嵌套对象
}
}
},
methods: {
updateObject() {
const newData = {
a: 100,
nested: { b: 200 } // 试图更新嵌套属性
};
// ❌ 错误做法:嵌套对象 { c: 3 } 会被完全覆盖
this.originalObj = Object.assign({}, this.originalObj, newData);
// 结果:nested.c 丢失 → { a:100, nested: { b:200 } }
}
}
解决方案
方案 1:递归深拷贝合并(推荐)
使用深拷贝工具库(如 lodash.merge
)递归合并嵌套属性:
npm install lodash.merge
import merge from 'lodash.merge';
methods: {
updateObject() {
const newData = {
a: 100,
nested: { b: 200 }
};
// ✅ 深度递归合并
this.originalObj = merge({}, this.originalObj, newData);
// 结果:{ a:100, nested: { b:200, c:3 } } (保留未修改的嵌套属性)
}
}
方案 2:手动合并嵌套属性
对每个嵌套层级显式合并:
methods: {
updateObject() {
this.originalObj = {
...this.originalObj,
a: 100, // 覆盖顶层属性
nested: {
...this.originalObj.nested, // 保留原嵌套属性
b: 200 // 覆盖特定嵌套属性
}
};
}
}
方案 3:Vue 的响应式 API(Vue 2/3 通用)
使用 Vue.set
(Vue 2)或直接赋值(Vue 3)确保响应性,同时手动合并:
// Vue 2
methods: {
updateObject() {
this.$set(this.originalObj, 'a', 100);
this.$set(this.originalObj.nested, 'b', 200);
// 未修改的 nested.c 自动保留
}
}
// Vue 3 (Composition API)
import { reactive } from 'vue';
const state = reactive({
originalObj: { a:1, nested: { b:2, c:3 } }
});
const updateObject = () => {
state.originalObj.a = 100;
state.originalObj.nested.b = 200; // 响应式更新,不影响 nested.c
};
方案 4:自定义深合并函数
function deepMerge(target, source) {
Object.keys(source).forEach(key => {
if (source[key] instanceof Object && target[key]) {
deepMerge(target[key], source[key]); // 递归合并嵌套对象
} else {
target[key] = source[key]; // 直接赋值非对象属性
}
});
return target;
}
// 使用
this.originalObj = deepMerge({ ...this.originalObj }, newData);
关键注意事项
- 响应式系统:
- Vue 2 中动态添加嵌套属性需用
this.$set()
触发响应。 - Vue 3 的
reactive
/ref
自动跟踪嵌套变化。
- 性能考量:
- 深拷贝对大型对象开销较大,优先考虑手动合并关键属性。
- 不可变数据:
- 需返回新对象时(如 Redux),用
lodash.merge
或递归展开符。
解决效果对比
方法 | 保留未修改属性 | 处理嵌套对象 | 响应式支持 | 复杂度 |
---|---|---|---|---|
lodash.merge | ✅ | ✅ | ✅ | 低 |
手动合并 | ✅ | ✅ | ✅ | 中 |
Vue 响应式 API | ✅ | ✅ | ✅ | 低 |
自定义深合并 | ✅ | ✅ | ⚠️ 需注意 | 高 |
Object.assign() | ❌ | ❌ | ✅ | 低 |
推荐:中小型对象用 手动合并(清晰直观),复杂嵌套结构用
lodash.merge
(安全高效)。
© 版权声明
本站资源来自互联网收集,仅供用于学习和交流,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!
THE END