Vue中对象赋值问题:对象引用被保留仅部分属性被覆盖的解决方案

Vue中对象赋值问题:对象引用被保留仅部分属性被覆盖的解决方案

在 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);

关键注意事项

  1. 响应式系统
  • Vue 2 中动态添加嵌套属性需用 this.$set() 触发响应。
  • Vue 3 的 reactive/ref 自动跟踪嵌套变化。
  1. 性能考量
  • 深拷贝对大型对象开销较大,优先考虑手动合并关键属性。
  1. 不可变数据
  • 需返回新对象时(如 Redux),用 lodash.merge 或递归展开符。

解决效果对比

方法保留未修改属性处理嵌套对象响应式支持复杂度
lodash.merge
手动合并
Vue 响应式 API
自定义深合并⚠️ 需注意
Object.assign()

推荐:中小型对象用 手动合并(清晰直观),复杂嵌套结构用 lodash.merge(安全高效)。

© 版权声明
THE END
喜欢就支持一下吧
点赞10赞赏 分享