一、什么是深拷贝?什么是浅拷贝?
深拷贝:修改变量的值不会影响原先变量的值,一般情况下基本数据类型都是深拷贝
let num1 = 2 ; //在内存中开辟了一块空间
let num2 = num1; //在内容中又新开辟了一块空间
num2 = 666 ; //num1依然是等于2
在这个例子中,把num1的值赋值给num2,修改了num2的值是不会影响到num1的值,所以num2=666后原先的num1的值仍然是2
浅拷贝:修改变量的值会影响原先变量的值,一般情况下引用数据类型就是浅拷贝
class Person{
name = '小明';
age = 18;
address = {
city:'重庆',
school:'重庆大学'
}
arr = [1,2,3]
}
let p1 = new Person()
let p2 = p1
p2.name = '小红'
p2.address.city = '上海'
p2.arr.push(4)
在这个例子中,p1 new了一个Person,并且和p1建立相等关系,然后只在p2里面修改了name,address,arr等属性的值,最后打印p1的时候我们会发现p1存的对象里面发生了改变
原因是p2和p1建立相等关系的时候,可以理解成p2存入了p1的地址值,而这个地址值指向的就是Person对象,所以我通过p2修改了对象里面的属性,然后通过p1去访问的时候,地址值没有发生变化,这两个p1和p2的地址都指向这个对象,所以通过p1访问到的对象已经被通过p2修改了
二、手写深拷贝
继续上面的例子,有的时候,我们想修改p2的值不影响到p1,其实可以直接一个一个的人为写入,大概就是这样的方式:
p2.name = p1.name
p2.age = p1.age
...
其实这个方法是有局限的,如果p1里面的属性太多了,一个一个写实属太愚蠢了。
其次,当我们写到p2.address = p1.address的时候,又对对象进行了引用,这里又变成了浅拷贝了
所以我们可以通过手写一个 深拷贝函数 来解决我们的问题
function deepCopy( target , source ){ //source代表你想要被拷贝的元素 , target代表你想要拷贝的元素
//1.for in 循环拿到 被拷贝元素 里面的属性
for(let key in source){
//2.拿到 被拷贝元素 里面的属性的值
let sourceValue = source[key]
//3.拿到遍历到的属性值的时候,需要判断这个属性值是不是引用类型
if(sourceValue instanceof Object){
//3.1如果是引用类型,做以下处理
let subTarget = new sourceValue.constructor
/**
*这里说一下:引用类型都会有一个constructor属性,数组的constructor会返回Array,对象的constructor会返回Object
*所以new sourceValue.constructor 就省去了判断它是数组还是对象
*/
target[key] = subTarget
//递归
deepCopy(subTarget,sourceValue)
}else{
//3.2如果不是引用类型,直接赋值就完事了
target[key] = sourceValue
}
}
}
这个函数读者们可以多琢磨一下,特别是里面的递归
一旦看懂,随便手写