浅拷贝和深拷贝

本文介绍了浅拷贝的概念,其优点包括快速复制、内存节省,以及浅拷贝的常见实现方式,如直接赋值、Object.assign()、扩展运算符和Array.prototype.slice()。同时,对比了深拷贝,强调了深拷贝对对象结构完整复制的重要性,提供了JSON.parse和lodash库的深拷贝方法,以及自定义递归深拷贝函数的实现。
  • 浅拷贝:浅拷贝是指仅复制对象的引用,而不复制对象本身。当对浅拷贝对象的属性进行修改时,原始对象和浅拷贝对象的相同属性会共享修改。换句话说,浅拷贝只复制对象的第一层结构,而不会递归复制所有嵌套对象的属性。

浅拷贝的优点:

  1. 快速复制对象:当需要快速复制一个对象,并且原始对象不包含引用类型数据(如嵌套对象、数组等)时,可以使用浅拷贝。

  2. 避免创建完全独立的副本:有时候并不需要创建一个完全独立于原始对象的副本,而是希望新对象与原始对象共享一些属性,这种情况下使用浅拷贝会更合适。

  3. 节省内存空间:由于浅拷贝只复制对象的引用而不复制整个对象及其内部对象,因此可以节省内存空间,特别是在处理大型对象或对象数量较多的情况下。

深拷贝的优点就是浅拷贝的缺点

浅拷贝是复制对象时,只复制对象的引用而不是对象本身。以下是一些常见的浅拷贝方式:

1.直接赋值:将一个对象赋值给另一个变量,这样它们会引用同一个内存地址。

// 直接赋值最特别,不管你obj里面有没有嵌套对象或数组,修改新对象就会影响原来的。
const obj = {a: 1, b: 2};
const shallowCopyObj = obj;

2.Object.assign()方法:将源对象的可枚举属性复制到目标对象。

const obj = {
  a: 1,
  b: {
    c: 2
  }
};

// 使用 Object.assign() 进行浅拷贝
const shallowCopyObj = Object.assign({}, obj);

console.log(shallowCopyObj); // { a: 1, b: { c: 2 } }

// 修改浅拷贝后的对象值
shallowCopyObj.a = 100; 
shallowCopyObj.b.c = 200;

console.log(obj); // { a: 1, b: { c: 200 } }
console.log(shallowCopyObj); // { a: 100, b: { c: 200 } }

// obj的a值没有变成100,因为在浅拷贝中,Object.assign()只会复制对象的属性值,对于属性值是基本类型(如数字、字符串等)的情况下,浅拷贝后的对象和原始对象的这些属性会是相互独立的。因此,在示例中,修改shallowCopyObj中a属性的值不会影响到obj中a属性的值,因为a是一个基本类型的属性值。但对于b属性,由于其值是一个对象引用,浅拷贝只复制了引用而不是实际的对象,因此修改shallowCopyObj.b.c会同时影响到obj.b.c,因为它们指向的是同一个对象。

3.扩展运算符(Spread Operator):将对象的可枚举属性复制到新对象中。

const obj = {a: 1, b: 2};
const shallowCopyObj = {...obj};

// 这里使用扩展运算符进行的浅拷贝得到的新对象对值进行修改不会影响obj
// 除非obj是这样的{a: 1, b: {c: 2}},改里面的才会有变化(这就是嵌套对象或数组的魅力)
shallowCopyObj.a = 3
shallowCopyObj.b = 4

console.log(obj); // {a: 1, b: 2}
console.log(shallowCopyObj); // {a: 3, b: 4}

4.Array.prototype.slice()方法(仅适用于数组):返回一个新数组,浅拷贝已有的数组。

const arr = [1, 2, 3];
const shallowCopyArr = arr.slice();
  • 深拷贝:深拷贝是指完全复制一个对象及其所有嵌套对象,新对象和原始对象的内存地址完全独立,彼此之间互不影响。深拷贝会递归复制所有嵌套对象的属性,确保复制了整个对象结构及其所包含的值。

    深拷贝的方式大概有以下几种:
    
    1.JSON.parse(JSON.stringify(obj))
    
    // JSON.stringify(obj)将JavaScript对象转换为JSON字符串,然后JSON.parse()将这个JSON字符串解析为一个新的JavaScript对象。由于这过程中生成的是全新的对象,所以实现了深拷贝,即复制了整个对象结构及其值,而不是只复制了对象的引用。
    
    2.使用lodash中的_.cloneDeep()方法实现深拷贝
    
    const _ = require('lodash');
    
    const obj = {
      a: 1,
      b: {
        c: 2,
        d: [3, 4]
      }
    };
    
    const deepCopyObj = _.cloneDeep(obj);
    
    console.log(deepCopyObj);
    
    3.使用递归遍历对象并复制属性实现深拷贝的方法
    
    function deepCopy(obj) {
      if (typeof obj !== 'object' || obj === null) {
        return obj;
      } // 'object'表示对象,包括obj和array。这段代码的作用是在递归深拷贝对象时,判断当前处理的属性是否为基本类型(如字符串、数字、布尔值等)或者为null,如果是的话,则直接返回该属性的值而不再进行递归复制,从而避免对基本类型和null进行不必要的深拷贝操作。
    
      let copy = Array.isArray(obj) ? [] : {}; // 这行代码用于创建一个空的数组或对象,取决于传入的obj是数组还是对象。这样可以确保在复制属性时,对于数组类型的属性会使用新的空数组来存储值,对于对象类型的属性会使用新的空对象来存储值,从而实现深拷贝的目的。
    
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
          copy[key] = deepCopy(obj[key]);
        }
      }
    
      return copy;
    }
    
    const obj2 = {
      a: 1,
      b: {
        c: 2,
        d: [3, 4]
      }
    };
    
    const deepCopyObj2 = deepCopy(obj2);
    
    console.log(deepCopyObj2);
    
    // 以上代码实现了一个递归的深拷贝函数deepCopy,通过判断对象是否为基本类型或者null来终止递归并直接返回该值。在递归过程中,对于每个属性,会先创建一个新的空数组或空对象来存储复制后的属性值,然后再递归调用deepCopy函数来复制属性值,确保复制了所有嵌套对象的属性,最终返回一个全新的深度克隆后的对象。这样就能够实现对原始对象的完全深拷贝。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值