深拷贝和浅拷贝的区别

一、浅拷贝(Shallow Copy)

1. 定义与特点
  • 只复制对象的一层属性:若对象的属性是基本类型(如 numberstring),则复制其值;若属性是引用类型(如对象、数组),则仅复制引用(内存地址),而非对象本身。
  • 新旧对象共享引用类型的属性:修改其中一个对象的嵌套属性,会影响另一个对象。
2. 实现方式

在 Vue 中,常见的浅拷贝方法有:

  • 扩展运算符(Spread Operator)const newObj = {...oldObj};
  • Object.assign()const newObj = Object.assign({}, oldObj);
  • 数组方法arr.slice()[...arr]
3. 示例代码
const original = {
  name: "Vue",
  version: { major: 3, minor: 2 }
};

const shallowCopy = { ...original }; // 浅拷贝

shallowCopy.version.major = 4;
console.log(original.version.major); // 输出 4,原始对象被修改!
4. 原理图解
原始对象 original
├── name: "Vue"
└── version: ┌── major: 3
             └── minor: 2

浅拷贝 shallowCopy
├── name: "Vue" (值复制)
└── version: ┌── major: 3 (引用复制,指向同一内存地址)
             └── minor: 2

二、深拷贝(Deep Copy)

1. 定义与特点
  • 递归复制对象的所有层级:创建一个完全独立的对象,与原始对象没有任何内存共享。
  • 修改新对象不会影响原始对象:无论嵌套多深,所有属性都是独立的。
2. 实现方式

在 Vue 中,实现深拷贝的方法有:

  • JSON 序列化与反序列化const deepCopy = JSON.parse(JSON.stringify(original));
    • 局限性:无法处理函数、正则、Date 对象、循环引用等。
  • 递归函数:手动编写递归逻辑遍历并复制所有属性。
  • 第三方库:如 lodash.cloneDeep()Vuex 的 clone() 工具。
3. 示例代码
const original = {
  name: "Vue",
  version: { major: 3, minor: 2 },
  update: () => console.log("Updated")
};

// 手动实现深拷贝函数
function deepCopy(obj) {
  if (obj === null || typeof obj !== "object") return obj;
  
  const clone = Array.isArray(obj) ? [] : {};
  
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepCopy(obj[key]); // 递归复制
    }
  }
  
  return clone;
}

const deepCopy = deepCopy(original);
deepCopy.version.major = 4;
console.log(original.version.major); // 输出 3,原始对象未被修改
4. 原理图解
原始对象 original
├── name: "Vue"
└── version: ┌── major: 3
             └── minor: 2

深拷贝 deepCopy
├── name: "Vue" (值复制)
└── version: ┌── major: 3 (递归创建新对象,内存地址不同)
             └── minor: 2

三、Vue 中的特殊场景

1. 响应式数据与拷贝
  • 浅拷贝丢失响应式:使用浅拷贝(如 Object.assign())复制 Vue 实例的响应式数据时,新对象的嵌套属性会失去响应式特性。
    export default {
      data() {
        return {
          user: { name: "Alice", age: 20 }
        };
      },
      methods: {
        updateUser() {
          // ❌ 浅拷贝,新对象的 age 不再是响应式的
          const newUser = Object.assign({}, this.user);
          newUser.age = 21; // 不会触发视图更新
        }
      }
    };
    
  • 深拷贝保持响应式:使用 Vue.set() 或 Vuex 的 clone() 工具进行深拷贝,确保新对象仍具有响应式特性。
2. 循环引用问题
  • 深拷贝的陷阱:若对象存在循环引用(如 obj.a = obj),递归深拷贝会导致栈溢出。
  • 解决方案:使用 WeakMap 记录已处理的对象,避免重复拷贝。
    function deepCopy(obj, map = new WeakMap()) {
      if (obj === null || typeof obj !== "object") return obj;
      if (map.has(obj)) return map.get(obj); // 处理循环引用
      
      const clone = Array.isArray(obj) ? [] : {};
      map.set(obj, clone); // 记录已处理的对象
      
      // 递归复制...
    }
    

四、性能考量

  • 浅拷贝:时间复杂度为 O(n),仅遍历一层属性,性能较高。
  • 深拷贝:时间复杂度为 O(m)m 为所有嵌套属性总数),递归操作开销大,慎用在大型数据结构上。

五、总结与最佳实践

场景浅拷贝深拷贝
数据隔离需求❌ 不适用(共享引用)✅ 完全隔离
响应式数据处理❌ 可能丢失响应式✅ 使用 Vue 专用工具
性能敏感场景✅ 高效❌ 开销大
包含函数 / 特殊对象✅ 正常处理❌ JSON 方法会丢失
循环引用✅ 无影响❌ 需特殊处理

建议

  • 优先使用浅拷贝:在无需完全隔离数据时,用 Object.assign() 或扩展运算符。
  • 谨慎使用深拷贝:仅在必要时使用 lodash.cloneDeep() 或手动实现,避免性能问题。
  • Vue 响应式数据:使用 Vue.set() 或 Vuex 的 clone() 工具处理嵌套对象。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端攻城狮001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值