深拷贝和浅拷贝的理解及其实现方式

深拷贝和浅拷贝

一、概念

浅拷贝:只拷贝最外面一层额数据;更深乘次的对象,只拷贝引用;

深拷贝:拷贝多层数据;每一层级别的数据都会拷贝;

拷贝引用的时候,是属于传址,而非传值

深拷贝和浅拷贝主要针对的是对象的属性是对象(引⽤类型),浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改变原对象。

二、 浅拷贝的实现方式

  • 方式1:直接赋值

    •  var c = {
       name:'tom',
       age:20
       }
       var d = c;
       c.name = 'jack';
       console.log(d);
  • 方式2:使用 for in

    •  var obj1 = {
           name: 'tom',
           age: 20,
           info: {
               msg: '是一个中国人'
           }
       }
       var obj2 = {};
       //for in
       for (var k in obj1) {
           obj2[k] = obj1[k];
       }
       console.log(obj2);
       obj1.info.msg = '虽然是个外国人,但是很向往中国';
       console.log(obj2);
  • 方式3:使用Object.assign(新数据,老数据)

    •  var obj1 = {
       name:'tom',
         age:20,
         info:{
           msg:'开心每一天'
         }
       }
       var obj2 = {};
       obj2=Object.assign(obj2,obj1);
       console.log(obj2);
       obj1.info.msg = '学习使你倍感快乐';
       console.log(obj2);
  • 方式4:函数库lodash的_.clone方法

    该函数库也有提供 _.clone 用来做 Shallow Copy,后面我们会再介绍利用这个库实现深拷贝。

    •  var _ = require('lodash');
       var obj1 = {
           a: 1,
           b: { f: { g: 1 } },
           c: [1, 2, 3]
       };
       var obj2 = _.clone(obj1);
       console.log(obj1.b.f === obj2.b.f);// true
       ​
  • 方式5:spread运算符 ...

    spread运算符是一个 es6/es2015 特性,它提供了一种非常方便的方式来执行浅拷贝,这与 Object.assign() 的功能相同。它不复制继承的属性或类的属性,但是它会复制ES6的 symbols 属性。

    •  let obj1 = { name: 'luck', say:{x:100,y:100}}
       let obj2= {...obj1}
       obj1.say.x = 200;
       obj1.name = 'tom'
       console.log('obj2',obj2) // obj2 { name: 'luck', say: { x: 200, y: 100 } }
  • 方式6:Array.prototype.slice()

    •  let arr = [ 1, 3, {username: 'luck'} ];
       let arr3 = arr.slice();
       arr3[2].username = 'tom'
       console.log(arr); // [ 1, 3, { username: 'tom' } ]
  • 方式7:Array.prototype.concat()

    •  let arr = [ 1, 3, {username: 'luck'} ];
       let arr2 = arr.concat();    
       arr2[2].username = 'tom';
       console.log(arr); //[ 1, 3, { username: 'tom' } ]

三、深拷贝的实现

  • 方式1:递归函数

    •  //写一个递归函数,实现检车每一个数据,如果是基本数据类型,则直接添加,如果是引用数据 类型,则递归引用数据类型,把里面的数据变成基本数据类型添加进去;
       var obj1 = {
         name:'tom',
         age:20,
         info:{
           msg:'多看多练'
         },
         color:['red','green','blue']
       };
       var obj2 = {};
       deepCopy(obj2,obj1);
       console.log(obj2);
       obj1.info.msg ='不练就不会';
       console.log(obj2);
       ​
       function deepCopy(newObj,oldObj) {
       for(var k in oldObj) {
         //获取数据
         var item = oldObj[k];
          if(item instanceof Array) {
           //判断item是否为为对象
           newObj[k] = [];
           deepCopy(newObj[k],item);
         }else if(item instanceof Object){
           //判断item是否为为对象
           newObj[k]= {};
            deepCopy(newObj[k],item);
       }else{
         //简单数据类型,直接赋值
         newObj[k] = item;
       }
       }
       }
  • 方式2:JSON.parse()|JSON.stringify();

    •  let arr = [ 1, 3, {username: 'kobe'} ];
       let arr4 = JSON.parse(JSON.stringify(arr));
       arr4[2].username = 'duncan'; 
       console.log(arr, arr4)

    • 这也是利用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 把字符串解析成对象,一去一来,新的对象产生了,而且堆内存中会开辟出一个新的区域存放新对象,实现深拷贝。

    • 这种方法虽然可以实现数组或对象深拷贝,但不能处理函数和正则,因为这两者基于 JSON.stringify 和 JSON.parse 处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

    • 例如下面的例子:

    •  let arr = [ 1, 3, {username: 'luck'}, function(){} ];
       let arr4 = JSON.parse(JSON.stringify(arr));
       arr4[2].username = 'tom'; 
       console.log(arr, arr4)
  • 方式3:函数库 lodash 的 _.cloneDeep 方法

    •  var _ = require('lodash');
       var obj1 = {
           a: 1,
           b: { f: { g: 1 } },
           c: [1, 2, 3]
       };
       var obj2 = _.cloneDeep(obj1);
       console.log(obj1.b.f === obj2.b.f);// false
  • 方式4:jQuery.extend() 方法

    •  $.extend(deepCopy, target, object1, [objectN])  //第一个参数为true,就是深拷贝
       ​
       var $ = require('jquery');
       var obj1 = {
           a: 1,
           b: { f: { g: 1 } },
           c: [1, 2, 3]
       };
       var obj2 = $.extend(true, {}, obj1);
       console.log(obj1.b.f === obj2.b.f); // false
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值