浅拷贝与深拷贝区别

什么是浅拷贝与深拷贝?

简单的说就是A复制了B之,后当我们去改变A的时候B也跟着改变了,那么就说明是浅拷贝,如果B没有改变,那么就说明是深拷贝。

栗子🌰
let A = ['cindy','lily'];
B = A;
A[0] = 'newcindy';
console.log(B) //  ['newcindy','lily'];

是不是很奇怪?明明是在复制之后改变A的为什么B会跟着变化呢?hhhh继续看下面的解释

基本数据类型和引用数据类型

基本数据类型:Number , String , Null , Undefined , Boolean;
基本类型-----键值存储在栈内存中
在这里插入图片描述

当复制基本类型的时候在内存区里面会在栈区开辟一个新的空间
所以当你此时修改a=2,对b并不会造成影响,因为此时的b已自食其力,翅膀硬了,不受a的影响了。当然,let a=1,b=a;虽然b不受a影响,但这也算不上深拷贝,因为深拷贝本身只针对较为复杂的object类型数据。

引用数据类型:Array , Objext , Function

引用数据类型 ---- 键存在栈内存中,值存在于堆内存中,但是栈内存会提供一个引用的地址指向堆内存中的值,我们以上面浅拷贝的例子画个图:

在这里插入图片描述

当b=a进行拷贝时,其实复制的是a的引用地址,而并非堆里面的值。
当我们 **a[0]=1 **时进行数组修改时,由于a与b指向的是同一个地址,所以自然b也受了影响,这就是所谓的浅拷贝了。

在这里插入图片描述
在这里插入图片描述

那,要是在堆内存中也开辟一个新的内存专门为b存放值,就像基本类型那样,岂不就达到深拷贝的效果了
在这里插入图片描述

这里就抛出本篇文章的核心问题:如何实现对引用数据类型进行拷贝时希望它开辟新的堆空间,而非引用原地址的堆空间。及所谓的深拷贝。

5. 深拷贝,是拷贝对象各个层级的属性(占坑)

举个板栗说明下:

let a=[1,2,3,4];
let b=a.slice();
a[0]=2;
console.log(b); // [1,2,3,4]

那是不是说 slice 方法也是深拷贝了,毕竟b也没受a的影响,上面说了,深拷贝是会拷贝所有层级的属性,还是这个例子,我们把a 再改改(添加了一个双层数组)

let a=[0,1,[2,3],4];
let b=a.slice();
a[0]=1;
a[2][0]=1;
console.log(b);// [0,1,[1,3],4]

拷贝的不彻底啊,b对象的一级属性确实不受影响了,但是二级属性还是没能拷贝成功,仍然脱离不了a的控制,说明slice根本不是真正的深拷贝。

第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。

同理,concat 方法与 slice 也存在这样的情况,他们都不是真正的深拷贝,而是属于浅拷贝,他们其实是披着羊(qian)皮(kao)的(bei)狼。这里需要注意。

那如何实现真正的深拷贝?继续看下面

5. 实现深拷贝的几种常见方法

1 使用递归去复制所有层级属性。

function deepClone(obj) {
    let objClone = Array.isArray(obj) ? [] : {};
    if (obj && typeof obj === "object") {
        for (key in obj) {
            if (obj.hasOwnProperty(key)) {
                //判断ojb子元素是否为对象,如果是,递归复制
                if (obj[key] && typeof obj[key] === "object") {
                    objClone[key] = deepClone(obj[key]);
                } else {
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}
// 测试代码
let a = [1, 2, [1,5], 4],
    b = deepClone(a);
a[0] = 2;
a[2][0] = 5;
console.log(a, b);

借用JSON对象的 parse和stringify

var a = [1, 2, [1,5], 4];
var b = JSON.stringify(a);
b = JSON.parse(b);
a[0] = 2;
a[2][0] = 5;
console.log(a, b);

可以看到,这下b是完全不受a的影响了。这里方法属于投机取巧,但是也确实可以实现深拷贝

附带说下,JSON.stringify与JSON.parse除了实现深拷贝,还能结合localStorage实现对象数组存储。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值