最近在准备面试题的时候和小伙伴聊到赋值是不是浅拷贝引发了我对这个问题的记录,在此之前一直以为赋值就是浅拷贝!(本文谈论的赋值、拷贝操作都是针对引用类型)
赋值不是浅拷贝!!!他们的关键在于浅拷贝新创建了一个对象
在讨论这个问题之前,读者们需要了解一下JavaScript将基本类型的变量存放在栈中,包括变量的标识符(可以理解为变量名)和变量的值;将引用类型的标识符和指向堆中的指针存放在栈中,变量的内容存放在堆中。
其中引用类型引申到了指针的概念,可以理解为引用类型例如对象的内容可能会有若干个,所以JavaScript规定把这个对象的内容放在堆中,然后在栈中存放了找到堆中内容的标识(可以理解为钥匙,导航等等)
一 赋值
// 赋值
let student = { name: '张三' }
let student1 = student
student1.name = '李四'
console.log(student.name) // 李四
console.log(student.name) // 李四
上例就是将student存在栈里面的指针赋值到了student1,他们两个指向的都是推中同一个空间,所以改变student1也会改变student
二 浅拷贝
let student = { name: '张三' }
function shallowClone(obj) {
let newObj = {}
for (let key in obj) {
// 拷贝的时候一般忽略掉继承的
if (obj.hasOwnProperty(key)) {
newObj[key] = source[key]
}
}
return newObj
}
let student1 = shallowClone(student)
student1.name = '李四'
console.log(student.name) // 张三
console.log(student.name) // 李四
上文也说到了赋值和浅拷贝的区别在于浅拷贝新创建了一个对象,这时候会重新在堆中开辟一个空间,存放拷贝来的内容,就不会影响之前的对象
三 深拷贝
let student = {
name: '张三',
familyInfo: {
mother: '张妈妈',
father: '张爸爸'
}
}
let student1 = shallowClone(student)
student1.familyInfo.father = '李爸爸'
console.log(student.familyInfo.father) // 李爸爸
console.log(student1.familyInfo.father) // 李爸爸
深拷贝与浅拷贝的区别在于一个引用类型内还有没有包含引用类型!例如上例的student对象内,还有一个familyInfo对象,如果我们使用浅拷贝对student进行拷贝,改变student1的familyInfo里面的father时也会改变student里面的值,这是因为浅拷贝里实现的方式还是赋值所以就会出现这个现象。
1 递归实现深拷贝
根据上文提到的内容,可以发现我们只需要对对象里的每一项都进行浅拷贝即可实现深拷贝,根据这个思路可以得出使用一个递归对对象里的每一个引用类型的项进行浅拷贝操作即可
2 JSON反序列化
可是使用JSON.parse(JSON.stringly())实现深拷贝,不过这种方法存在缺陷,感兴趣的读者可以自行去网上搜一下缺陷
- 以上只是读者自己的一些理解,如果有问题欢迎大家指出