深拷贝和浅拷贝主要是针对对象的属性是对象(引用类型)
- 浅拷贝:拷贝的是栈中的地址,所以当修改其中的一个,另一个也会修改
- 深拷贝:拷贝的值一样,但是指向的地址不一样。所以当修改其中一个并不影响另外一个
浅拷贝 Object.assign()
只是一个浅拷贝,对于基本类型可以直接替换,对于引用类型就会有问题
let target = {}
let source = {
a: 1,
b: 2
}
Object.assign(target, source)
console.log(target) // { a: 1, b: 2 }
此时我们看到以上代码并没有问题,下面我们把代码写的复杂一些再看一下
let target = {
a: {
b: {
c: 1
}
e: 2,
f: 3
}
}
let source = {
a: {
b: {
c: 1
}
e: 2
}
}
Object.assign(target, source)
console.log(target) // 我们可以看到打印出来的数据 f 丢失了
- Object.assign 在拷贝对象的时候是有问题的,对于基本数据类型是没有问题的,但是对于引用数据只是把地址直接指过去,如果结构很复杂有些属性会直接丢失,
- 在使用Object.assign去复制一个比较复杂的结构并不安全,
- Object.assign 只是一个浅拷贝并不是深拷贝
浅拷贝
obj1 = {
name: 'UU',
age: 1
}
let obj2 = obj2
obj1.age = 18
console.log(obj1)
console.log(obj2)
- 当 obj1 发生变化的时候obj2 也发生了变化,这种叫做浅拷贝
- 相当于obj1 和obj2 指向了同一块内存地址
深拷贝
let a = 5
let b = a
a = 6
console.log(a, b)
- 当 a 发生变化的时候 b 并没有发生变化,这个我们可以叫做深拷贝,两个值互相并不影响
下面我们使用 JSON.parse() JSON.stringify() 实现一个深拷贝
obj1 = {
name: 'UU',
age: 1
}
let str = JSON.stringify(obj1)
let obj2 = JSON.parse(str)
obj2.age = 18
console.log(obj2)
- 我们可以看到 age 还是 1 说明obj1 和obj2 在堆内存里面是两个不同的内存地址,所以他们两个互相不干扰
下面我们封装一个函数来实现以下深拷贝
let checkType = data => {
return Object.prototype.toString.call(data).slice(8, -1)
}
checkType({})
let deepClone = target => {
let targetType = checkType(target)
let result
if(targetType === 'Object') {
result = {}
}else if(targetType === 'Array') {
result = []
}else {
return target
}
for(let i in target){
let value = target[i]
let valueType = checkType(value)
if(valueType === 'Object' || valueType === 'Array'){
result[i] = deepClone(value)
}else{
result[i] = value
}
}
return result
}
let arr1 = [1, 2, {age: 18}]
let arr2 = deepClone(arr1)
arr2[2].age = 4
console.log(arr1)