js中的深浅拷贝

堆和栈

其实深拷贝和浅拷贝的主要区别就是其在内存中的存储类型不同。

堆和栈都是内存中划分出来用来存储的区域。

栈(stack)为自动分配的内存空间,它由系统自动释放;而堆(heap)则是动态分配的内存,大小不定也不会自动释放。

数据类型

数据类型分为:基本数据类型 和 引用数据类型。

基本类型

基本数据类型存放在栈中。

存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配,是直接按值存放的,所以可以直接访问。

基本类型的比较是值的比较,只要它们的值相等就认为他们是相等的。

比较的时候最好使用严格等,因为 == 是会进行类型转换的,比如:

 var a = 1
 var b = true
 console.log(a == b);   // true

引用类型

引用类型存放在堆中。

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

 var person1 = {name:'小明'};
 var person2 = {name:'小红'};
 var person3 = {name:'小军'};

 

引用类型的比较是引用的比较

所以每次我们对 js 中的引用类型进行操作的时候,都是操作其对象的引用(保存在栈内存中的指针),所以比较两个引用类型,是看其的引用是否指向同一个对象。例如:

 var a = [1,2,3] 
 var b = [1,2,3]   
 console.log(a === b); // false

 虽然变量 a 和变量 b 都是表示一个内容为 1,2,3 的数组,但是其在内存中的位置不一样,也就是说变量 a 和变量 b 指向的不是同一个对象,所以他们是不相等的。

传值与传址

了解了基本数据类型与引用类型的区别之后,我们就应该能明白传值与传址的区别了。
在我们进行赋值操作的时候,基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。例如:

 var a = 10
 var b = a
 a ++ 
 console.log(a); // 11
 console.log(b); // 10

 所以说,基本类型的赋值的两个变量是两个独立相互不影响的变量。

但是引用类型的赋值是传址。只是改变指针的指向,例如,也就是说引用类型的赋值是对象保存在栈中的地址的赋值,这样的话两个变量就指向同一个对象,因此两者之间操作互相有影响。例如:

 var a = {}; // a保存了一个空对象的实例
 var b = a;  // a和b都指向了这个空对象
 a.name = '小明';
 console.log(a.name); // '小明'
 console.log(b.name); // '小明'
 b.age = 22;
 console.log(b.age); // 22
 console.log(a.age); // 22
 console.log(a == b); // true 

 浅拷贝

赋值(=)和浅拷贝的区别

那么赋值和浅拷贝有什么区别呢,我们看下面这个例子:

var obj1 = {    
            'name': '小红',
            'age': '18',
            'language': [1, [2, 3], [4, 5]],
        };
        var obj2 = obj1;
        //赋值操作得到    
        var obj3 = shallowCopy(obj1);
        //浅拷贝得到    
        function shallowCopy(obj) {
            var dst = {};
            for (var prop in obj) {
                if (obj.hasOwnProperty(prop)) {
                    dst[prop] = obj[prop];
                }
            }
            return dst;
        }
        obj2.name = "小明";
        obj3.age = "20";
        obj2.language[1] = ["二", "三"];
        obj3.language[2] = ["四", "五"];

  console.log(obj1);   // { name:'小明', age:'18', language:[ 1, ["二","三"], ["四","五"]] }
  console.log(obj2);   // { name:'小明', age:'18', language:[ 1, ["二","三"], ["四","五"]] }
  console.log(obj3);   // { name:'小红', age:'20', language:[ 1, ["二","三"], ["四","五"]] }

这是因为浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。所以就会出现改变浅拷贝得到的 obj3 中的引用类型时,会使原始数据得到改变。

深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象,

浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象

深拷贝

深拷贝是对对象以及对象的所有子对象进行拷贝。

Js自带的深拷贝方法

1、Array

slice()、concat、Array.from()、... 操作符:只能实现一维数组的深拷贝

 var arr1 = [1, 2, [3, 4]]
 var arr2 = arr1.slice();
 console.log(arr1); //[1, 2, [3, 4]]
 console.log(arr2); //[1, 2, [3, 4]]
 arr2[0] = 2 
 arr2[2][1] = 5; 
 console.log(arr1); //[1, 2, [3, 5]]
 console.log(arr2); //[2, 2, [3, 5]]

2、Object

Object.assign():只能实现一维对象的深拷贝

 var obj1 = {x: 1, y: 2}
 var obj2 = Object.assign({}, obj1);
 console.log(obj1) //{x: 1, y: 2}
 console.log(obj2) //{x: 1, y: 2}
 obj2.x = 2; //修改obj2.x
 console.log(obj1) //{x: 1, y: 2}
 console.log(obj2) //{x: 2, y: 2}
 var obj1 = {    
      x: 1,     
      y: { 
         m: 1    
      }
 };
 var obj2 = Object.assign({}, obj1);
 console.log(obj1) //{x: 1, y: {m: 1}}
 console.log(obj2) //{x: 1, y: {m: 1}}
 obj2.y.m = 2; //修改obj2.y.m
 console.log(obj1) //{x: 1, y: {m: 2}}
 console.log(obj2) //{x: 1, y: {m: 2}}

 JSON.parse(JSON.stringify(obj)):可实现多维对象的深拷贝,但会忽略undefined、任意的函数、symbol 值,循环引用会报错,相同的引用会被重复复制

 var obj1 = {    
       x: 1,    
       y: {       
          m: 1    
        },    
       a:undefined,    
       b:function(a,b){      
           return a+b    
       },    
       c:Symbol("foo")
 };
 var obj2 = JSON.parse(JSON.stringify(obj1));
 console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: , c: Symbol(foo)}.
 console.log(obj2) //{x: 1, y: {m: 1}}
 obj2.y.m = 2; //修改obj2.y.m
 console.log(obj1) //{x: 1, y: {m: 1}, a: undefined, b: , c: Symbol(foo)}
 console.log(obj2) //{x: 2, y: {m: 2}}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

我是来写bug的吧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值