JS直接赋值、浅拷贝和深拷贝的区别

        首先要知道JS的数据类型分为基本数据类型(String、Number、Boolean 等)和引用数据类型(Object、Array、Function)。基本数据类型值的存储是直接存储在栈内存中的,而引用数据类型值的储存是不同的,值是存储在堆内存中,不是直接存储在栈内存中,栈内存存储的是值的引用地址,可以通过引用地址找到堆内存中所对应的值。看图可以更好的理解。

现在有a对象,然后变量b等于a。

let a = { name : 'lisi' }
let b = a

他们的值在内存中是这样存储的。

有了对基本数据类型和引用数据在内存的储存方法,就可以继续了。

一、直接赋值

        如果是基本数据类型的直接赋值,得到的是一个新的值,会在栈内存中新开辟一个空间储存赋值的值,所以不用考虑浅拷贝和深拷贝。

        而引用数据类型的直接赋值,得到的是一个地址的引用,就会出现下面的情况。

let obj1 = {
  name: 'zhangsan',
  age: 18
}
let obj2 = obj1
obj2.name = 'lisi'
console.log('obj1:',obj1);
console.log('obj2:',obj2);

 

 

       

        原因就是直接赋值后,obj2得到的只是obj1值的引用地址,此时obj1和obj2引用地址一样,指向堆内存的值也是同一个。所以obj2修改name属性后,obj1对应的值也改变了,因为是同一个值。

二、浅拷贝

        浅拷贝就是为了解决上面的情况,让赋值后的对象拿到的是新的引用地址和新的值,一人一份,不用两个对象用同一份值。但是都叫浅拷贝了,意思就是没有完全一人一份,有的地方还是会共用同一份值。比如一个对象的一个属性值是数组或对象(相当于对象里还有一个对象),而浅拷贝后,拷贝到的这个属性得到的还是同一个引用地址。

        浅拷贝只能拷贝一层的基本数据类型,多层后就无法拷贝到了,如下例子。(我使用了lodash库中的 _clone方法实现浅拷贝,使用前记得引入,而ES6中的Object.assign也可以进行浅拷贝。)

let obj1 = {
  name: 'zhangsan',
  age: 18,
  friend: {
    name: 'xiaobai'
  }
}
let obj2 = _.clone(obj1) //进行浅拷贝
obj2.name = 'lisi'       //修改 obj2.name 看看obj1.name 是否改变
obj2.friend.name = 'afu' //修改 obj2.friend.name 看看 obj1里的是否一起改变
console.log('obj1:', obj1);
console.log('obj2:', obj2);

        可以看出来浅拷贝解决了直接赋值产生的问题,但是对于引用数据类型里有其他引用类型数据类型的时候,并不能完全的拷贝,相当于只能拷贝一层,而深拷贝就可以解决这个问题

三、深拷贝

        深拷贝就是可以给你一份一模一样的值,会在堆内存中开辟一个新的区域存放新的值,新的值和原值不存在共享内存的情况,不论你这个引用数据类型里嵌套了多少层,都可以拷贝给你,实现真正的拷贝。直接看例子:(我使用lodash库的_.cloneDeep方法实现深拷贝)

let obj1 = {
  name: 'zhangsan',
  age: 18,
  friend: {
    name: 'xiaobai',
    animal: ['dog']  //数组也是引用类型
  }
}
let obj2 = _.cloneDeep(obj1) //进行深拷贝
obj2.friend.animal[0] = 'cat' //修改了第三层的数据
console.log('obj1:', obj1);
console.log('obj2:', obj2);

 

 

        可以发现修改了obj2的值,obj1的中的值没有跟着变化,表示这两个对象是完全不同的了,这就是深拷贝的作用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值