js浅拷贝、深拷贝

前言

本文主要简单讲一下什么是浅拷贝、什么是深拷贝、深拷贝与浅拷贝的区别,以及怎么进行深拷贝和怎么进行浅拷贝。

一浅拷贝和深拷贝的区别主要是其在内存中的存储类型不同,或是传值与传址的区别

第一步先了解javascript的7中内置类型:
基本数据类型:存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。

  1. 空值(null)
  2. 未定义(undefined)
  3. 布尔值(boolean)
  4. 数字(number)
  5. 字符串(string)
    6.(symbol,ES6新增)

引用类型:存放在堆内存中的对象,变量实际上是一个存放在栈内存的指针,这个指针指向堆内存中的地址。每个空间大小不一样,要根据情况开进行特定的分配。

  1. 对象(object)

二 栈(stack)和堆(heap)

stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不定也不会自动释放。
基本类型存放在栈中
引用类型存放在堆中
当我们需要访问引用类型(如对象,数组,函数等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

例子

      var a = [1,2,3,4,5];
      var b = a;
      var c = a[0];
      alert(b);//1,2,3,4,5
      alert(c);//1
      //改变数值        
      b[4] = 6;
      c = 7;
      alert(a[4]);//6
     alert(a[0]);//1

从上面我们可以得知,当我改变b中的数据时,a中数据也发生了变化;但是当我改变c的数据值时,a却没有发生改变。
这就是传值与传址的区别。因为a是数组,属于引用类型,所以它赋予给b的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象。而c仅仅是从a堆内存中获取的一个数据值,并保存在栈中。所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。

三浅拷贝

前面已经提到,在定义一个对象或数组时,变量存放的往往只是一个地址。当我们使用对象拷贝时,如果属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即'父子对象发生了关联',两者的属性值会指向同一内存空间。

    var a = {
          key1:"11111"
      }
      function Copy(p) {
         var c = {};
          for (var i in p) { 
            c[i] = p[i];
         }
         return c;
   }
      a.key2 = ['小辉','小辉'];
      var b = Copy(a);
   b.key3 = '33333';  
      alert(b.key1);     //1111111
     alert(b.key3);    //33333
     alert(a.key3);    //undefined

a对象中key1属性是字符串,key2属性是数组。a拷贝到b,12属性均顺利拷贝。给b对象新增一个字符串类型的属性key3时,b能正常修改,而a中无定义。说明子对象的key3(基本类型)并没有关联到父对象中,所以undefined。
  但是,若修改的属性变为对象或数组时,那么父子对象之间就会发生关联。从以上弹出结果可知,我对b对象进行修改,a、b的key2属性值(数组)均发生了改变。
  原因是key1的值属于基本类型,所以拷贝的时候传递的就是该数据段;但是key2的值是堆内存中的对象,所以key2在拷贝的时候传递的是指向key2对象的地址,无论复制多少个key2,其值始终是指向父对象的key2对象的内存空间。

深拷贝

或许以上并不是我们在实际编码中想要的结果,我们不希望父子对象之间产生关联,那么这时候可以用到深拷贝。既然属性值类型是数组和或象时只会传址,那么我们就用递归来解决这个问题,把父对象中所有属于对象的属性类型都遍历赋给子对象即可。测试代码如下:

function Copy(p, c) {
        var c = c || {};
        for (var i in p) {
          if (typeof p[i] === 'object') {
             c[i] = (p[i].constructor === Array) ? [] : {};
             Copy(p[i], c[i]);
          } else {
             c[i] = p[i];
          }
        }
        return c;
  }    
    a.key2 = ['小辉','小辉'];
    var b={};
    b = Copy(a,b);        
    b.key2.push("大辉");
    alert(b.key2);    //小辉,小辉,大辉
    alert(a.key2);    //小辉,小辉
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容