这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战
深浅拷贝的区别
浅拷贝
就是拷贝指向对象的指针,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这个内存空间的所有指针需要重新定义,不然会造成野指针错误。
深拷贝
一个引用对象一般来说由两个部分组成:一个具名的Handle,也就是我们所说的声明(如变量)和一个内部(不具名)的对象,也就是具名Handle的内部对象。它在Manged Heap(托管堆)中分配,一般由新增引用对象的New方法是进行创建。深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。比较典型的就是Value(值)对象,如预定义类型Int32,Double,以及[结构](struct),(Enum)等。
其实看这个意思,我们得到的结论是深浅拷贝的最主要区别在于是否存在独立的内存空间。
浅拷贝例子
let obj1 = { a: 1 }
let obj2 = obj1
obj2.a = 2
obj2.b = 3
console.log(obj1)
console.log(obj2)
console.log(obj1 === obj2)
当我们做了如上赋值的时候,obj2就是obj1的浅拷贝,他们的指针指向同一块空间,当obj2修改的时候,尽管没有修改obj1,obj1还是改变了,所有我们得到如下
深拷贝例子
通过网上的查找找到了使用JSON.parse/JSON.stringify可以实现深拷贝,下面是例子
let obj1 = {a : 1}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.a = 2
obj2.b = 3
console.log(obj1)
console.log(obj2)
obj1.a = 4
obj1.c = 5
console.log(obj1)
console.log(obj2)
由上图我们发现,通过json赋值后的obj2的改变并没有影响到obj1
但这样的拷贝在复杂的对象中也适用吗?如下
let obj1 = {
a: 1,
b: function() {
console.log(this.a)
}
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.a = 3
console.log(obj1)
console.log(obj2)
console.log(obj2.b())
然而我们得到的结果确实如下
原因是在转化的过程中,undefined、function、symbol会被忽略掉。
然后我们想下怎么拷贝可以达到将函数也同样拷贝的效果
思路
- 首先,我们要判断当前对象的类型,是数组还是obj
- 其次,判断子属性是否存在
- 在子属性存在的情况下,同样要判断子属性的类型,当为数组的时候就直接拷贝,为对象的时候就再次循环上述操作
function deepClone(obj) {
const objParam = obj.constructor === Array ? [] : {}
for(let keys in obj) {
if(obj.hasOwnProperty(keys)) {
if (obj[keys] && typeof obj[keys] === 'object') {
objParam[keys] = obj[keys].constructor === Array ? [] : {}
objParam[keys] = deepClone(obj[keys])
} else {
objParam[keys] = obj[keys]
}
}
}
return objParam
}
let obj1 = {
a: 1,
b: function() {
return this.a
}
}
let obj2 = deepClone(obj1)
obj2.a = 2
obj2.c = function() {
console.log('this is c')
}
console.log(obj1)
console.log(obj2)
console.log(obj2.c())
结果如下: