有很多小伙伴会对深浅拷贝有疑惑,到底什么是深拷贝什么是浅拷贝呢?
在这个之前,我们要知道堆与栈分别是什么。
栈:String、Number、Boolean、Null、Underined
堆:Function、Array、Object
然后我们根据上面的理解来认知接下来的深拷贝与浅拷贝
什么是浅拷贝
两个引用类型指向同一个地址,改变一个,另一个也会随之改变
我们来看一个demo
var c = { num: 18 };
var d = c;
c.num = 20;
console.log('c:', c, 'd:', d);
我们看一下浏览器
上面其实理解非常简单,我声明了一个对象c,因为对象复杂数据类型,存放于堆内存的,所以在栈中留下了一个指向地址指向堆中的num=18,然后我在栈中声明了一个变量d,并将c赋值给d,c是指向堆中的num,所以,d拷贝了c的指向路径当c指向的num改变了,d也会随着改变,这就是浅拷贝
我们可以看一下这个图理解一下
什么是深拷贝
复制后引用类型指向一个新的内存地址,两个对象改变互不影响
我们看一下demo
var c = { num: 18 };
var d = JSON.parse(JSON.stringify(c))
c.num = 20;
console.log('c:', c, 'd:', d);
再去观察一下浏览器
这里我们也可以这样去理解,我们在栈中声明了一个对象c并指向于堆中的num=18。
然后再在栈中声明一个变量d,然后使用序列化与反序列化的操作,将对象c深拷贝给d
然后再去修改原来c所指向的堆中的num。这两个对象是互不干扰的,因为是深拷贝的缘故,所以这样我们就实现了对象的深拷贝与浅拷贝
我们再思考一下,如果是基础数据类型的赋值他是属于深拷贝还是浅拷贝呢?
答案是:赋值既不是深拷贝也不是浅拷贝,只是跟深拷贝是类似
我们简单在浏览器看一下就知道,因为这是简单数据类型,不用指向堆的地址,所以可以直接的进行赋值,所以它并不是深拷贝与浅拷贝
我们再看一下,数组的方法:concat、slice是浅拷贝还是深拷贝?
concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本
写一个demo
var arr1 = [1,2,3];
var arr2 = arr1.concat();
arr2[1] = 10;
console.log("数组的原始值:" + arr1 );
console.log("数组的新值:" + arr2 );
看看浏览器打印
通过JS的concat方法,改变拷贝出来的数组的某项值后,对原来数组没有任何影响
由于数组内部属性值为引用对象,因此使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址