浅拷贝和深拷贝

129 阅读4分钟

黑松、蓝天、白雪

上一篇文章还是沉浸再要过年的喜庆气氛当中,但怎么都没有想到疫情是如此的严重,还是希望各位珍爱生命远离病毒吧!,回顾一下过去的几个月,还好像再眼前,不禁感叹道时间过得实在太快,最近也在持续关注各大厂的招聘情况,感觉疫情之下,机会更少了,要求更多了,但是话又说回来,上天对每个人都是公平的,机会是对等的,只有不断地充实自己才是王道。所以我又来给各位灌毒鸡汤来了,干了这碗,咱们开始讲今天的主题,也就是我最近再啃得原生js。

  1. 数据类型

    数据类型分为两种,基本数据类型和引用数据类型,基本数据类型存储直接存储在栈内存中,而对于引用类型来说,它在栈内存中仅仅存了一个引用,而真正得数据存储在堆内存中。看一下示例图

    引用类型就是存在堆内存中,两个对象是在用指针指向同一个堆内存得地址

  2. 浅拷贝

    既然要说深拷贝,那估计大家都知道肯定有浅拷贝啊,那什么是浅拷贝呢?

    // 基本类型得的浅拷贝
    var a = 5 ; 
    var b = a ;
    b = 3
    console.log(a);  // 5 
    console.log(b)  // 3 
    
    // 引用类型的浅拷贝
    var  obj = {
        name:'yuhior',
        age:18,
        class:'三年二班'
    }
    var obj2 = obj ;
    obj2.name = '张三了';
    console.log(obj.name)  // 张三了
    console.log(obj2.name)  // 张三了 
    

    上边我们发现 基本类型由于存储在栈内存中,是两个相对独立的数据,所以更改一个另一个并不会改变,但是引用类型的obj 改变的name ,将 obj 赋予 obj2 的时候,我们其实仅仅只是将 obj 存储在栈堆中的的引用赋予了 obj2 ,而两个对象此时指向的是在堆内存中的同一个数据,所以当我们修改任意一个值的时候,修改的都是堆内存中的数据。我称 这种 = 只拷贝对象的引用,而不深层次的拷贝对象的值叫浅拷贝

  3. 深拷贝

    在实际项目中,尤其是使用vue ,数据双向绑定的框架时,尤其明显的能感知到每个对象指向一个堆内存,一个改变另一些全部改变,根本不便于操作 。所以我们要深拷贝,我们要自由 哈哈哈哈哈。深拷贝就不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一下,形成一个全新的堆内存存储。

  4. 深拷贝的实现方法

    • 低配版 JSON.stringify()和JSON.parse()

      var  obj = {
          name:'yuhior',
          age:18,
          class:'三年二班'
      }
      var obj2 = JSON.parse(JSON.stringify(obj));
      obj2.name = '张三了';
      console.log(obj.name)  // yuhior
      console.log(obj2.name)  // 张三了 
      

      缺点:不可以拷贝undefined 、function 、RegExp类型 的

      var obj = undefined;
      var obj1 = JSON.parse(JSON.stringify(obj));
      // 直接报错  
      // VM4562:1 Uncaught SyntaxError: Unexpected token u in JSON at position 0
      //     at JSON.parse (<anonymous>)
      //    at <anonymous>:1:17
      
    • Object.assign (target,source)

       var obj1 = {
          a: 1,
          b: 2,
          c: 3
      }
      var obj2 = Object.assign({}, obj1);
      obj2.b = 5;
      console.log(obj1.b); // 2
      console.log(obj2.b); // 5
      

      缺点:可以看到对于一层对象来说是没有任何问题的,但是如果对象的属性对应的是其它的引用类型的话,还是只拷贝了引用,修改的话还是会有问题

      var obj1 = {    // 来一个多层的
          a: 10,
          b: 11,
          c: ['a','b','c']
      }
      var obj2 = Object.assign({}, obj1);
      obj2.c[1] = 6;
      console.log(obj1.c); // ["a", 6, "c"]
      console.log(obj2.c); // ["a", 6, "c"] 
      // 两个都改变了说明还是引用了
      
    • 递归拷贝 ,也是面试官常考的 ,我们还是先来举个栗子,毕竟学习了,还能吃栗子还是很爽的把 ,哈哈哈哈

      //  写一个深拷贝的方法把
      function depClone(tar){
          let result;
          // tar如果是一个对象的话
          if(typeof(tar)==='object'){
              // typeof(Array) ==='object';  如果是一个数组
              if(Array.isArray(tar)){
                  result = []; // 将result 设定为数组 并执行遍历
                  for(let i in tar){
                      //进行克隆数组中的每一项
                      result.push(deepClone(tar[i])); 
                  }
               //  如果是null的话,那就直接赋值null
              }else if(tar === null){ 
                  result = null;
              // 判断如果当前的值是一个RegExp对象的话,直接赋值
              }else if(tar.constructor===RegExp){
                   result = tar;
               //最后就是普通的对象了,直接进行循环,递归赋值所有的值
              }else{
                  result = {};
                  for(let i in tar){
                      result[i] = deepClone(tar[i]);
                  }
              }
          // 如果不是对象的话,那就是一个基本类型了,那就直接赋值被
          }else{
              result = tar ;
          }
          // 终于到回归结果的时候啦
           return result;
      }
      

      锅都准备好啦,那就赶紧做个饭试一下把!!!

      // 有一个对象 多层嵌套,还含有undefined  
      var obj = {
          a:{
              b:/a/,
              c:undefined,
              d:null
          },
          b:function(){
              console.log(this.a);
          },
          c:[
              {
                  b:/a/,
                  c:undefined,
                  d:null 
              },
              'a',
              3
          ]
      };
      var obj1 = deepClone(obj);
      console.log(obj2);  //  相信你勤快的小手,自己打印一下看看把