深浅拷贝
深浅拷贝这个东西是十分基础的,它涉及到了堆栈的问题,如果想要理解深浅拷贝的区别,首先要明白堆和栈的区别。
所以我们先来说一说堆和栈的区别:
堆和栈你可以当成计算机内存中的两个不同的大盒子,不同的数据类型放在不同的盒子里。
我们都知道数据类型分为两种:简单数据类型和复杂数据类型。复杂数据类型就是数组、对象、函数这三个,其他的就是简单数据类型。简单数据类型呢就是放在栈中,复杂数据类型的内容放在堆中。如图所示
我们在调用数据的时候,其实都是调用的栈中的内容,但是复杂数据类型的数据存在了堆中,那是怎么调用他的数据呢?其实在定义复杂数据类型的时候,系统在栈中放了一个对应的堆中数据的地址。我们调用复杂数据类型时其实调用的是栈中的地址,然后系统根据这个地址找到了堆中的对应数据,然后进行输出。
明白了这个关系之后,我们再来看看深拷贝和浅拷贝
首先来看看浅拷贝:
<script>
var arr1=[1,2,3,4,5,6];
var arr2=[];
arr2=arr1;
arr1[0]=99999;
console.log(arr2);
</script>
我们定义了两个数组(复杂数据类型),第二个为空数组,我们让这个空数组 = 第一个数组,然后我们改变第一个数组中的数据,输出第二个数组看看结果。
我们发现第二个数组的内容也改变了,这个就是浅拷贝,第二个数组(空数组)会受到第一个数组的影响。
这是为什么呢?原因很简单:上面我们说了复杂数据类型引用的时候其实是引用栈中的地址,arr2 = arr1其实赋值的不是arr1中的数据,而是其栈中的地址,他们两个共享同一个堆中的数据内容,你说arr1内容改变了,arr2改变不改变?
叫它浅拷贝也正是因为它只拷贝了个皮毛,东西还是人家的。
再来看看深拷贝:
<script>
var arr1=[1,2,3,4,5,6];
console.log(arr1);
var arr3=[];
for(var i = 0;i<=arr1.length-1;i++){
arr3.push(arr1[i]);
}
arr1[1]=44444444;
console.log(arr3);
</script>
同样定义两个数组,第二个为空数组,我们循环赋值拿到第一个数组中的数据内容,然后赋值给第二个空数组,再改变第一个数组中的数据内容,看看第二个数组的变化。
我们发现第一个数组中的数据内容改变了,但是第二个数组的数据内容没有改变,这是因为我们循环拿到的是第一个数组堆中的数据内容,而不是栈中的地址,第二个数组其实是相当于在堆中创建了一个新的地方存放他自己的数据,调用第二个数组的时候是调用的他自己的堆中的地址,他们两个不再是调用同一个地址了。
这就是深拷贝,他不再是拷贝了一个皮毛,而是将对方的东西完完全全复制了一份过来,所以叫深拷贝。
总结:
浅拷贝:拷贝一个皮毛,东西不是自己的,是别人的,别人变了他也得变
深拷贝:拷贝得十分完美,东西变成了自己的,自己想怎么用别人管不着,别人变了不关自己什么事儿。
以后我们会经常用深拷贝来实现项目效果,这两个概念必须搞明白。