对const定义的对象进行复制时,会出现一些问题 :
const obj = {
name: 'jack',
age: 12
}
const o = obj
console.log(o) // {name:'jack',age:12}
o.age = 20
console.log(o,obj) // {name:'jack',age:20} {name:'jack',age:20}
明明没有直接修改obj中的数据,但是里面的值却发生了变化 , 这是因为 创建对象时 , 是直接把栈中的一个地址给了obj , 这个地址指向堆中的真正对象值 , 然后又创建一个对象 o 指向了obj ,就是相当于让 o 也指向了栈中这个地址,那么在修改o中的数据时 , 对应堆中的数据会发生改变 ,再次访问 obj时 , 里面的数据就变了。所以说直接复制对象还是有很大风险的 , 这时候就需要我们的拷贝
深浅拷贝只针对引用类型
深浅拷贝只是针对引用类型的,因为引用类型是存放在堆内存中,在栈地址有一个或者多个地址来指向推内存的某一数据
浅拷贝
实现浅拷贝的常见方法 :
拷贝对象 Object.assign(o,obj) / { …obj }
拷贝数组 Array.prototype.concat() / [ …arr ]
const obj = {
name: 'kitten',
age: 18
}
const o = { ...obj }
console.log(o) // {name:'kitten',age:18}
o.age = 20
console.log(o,obj) // {name:'kitten',age:20} {name:'kitten',age:12}
//or
Object.assign(o2,obj)
console.log(o2) // {name:'kitten',age:12}
o2.age = 20
console.log(o2,obj) // {name:'kitten',age:20} {name:'kitten',age:20}
通过浅拷贝我们确实可以解决一些实际问题,但是当遇到下面的场景时,它仍然无法解决
const obj = {
age: 12,
info:{
name:'kitten'
}
}
const o = { ...obj }
console.log(o) // { age:12 , info: { name: 'kitten' } }
o.info.name = 'lucy'
console.log(o,obj) // { age:12 , info: { name: 'lucy' }} { age:12 , info: { name: 'lucy' }}
解释一下 , 其实 这里的o.info 和 obj.info 还是指向同一个栈中的地址 , 这个栈中的地址也指的是堆中的同一个对象 , 所以在修改o.info时还是会出现问题
应该说,浅拷贝拷贝的就是值,拷贝对象的时候拷贝的是对象在栈中的地址 ,而不是地址指向的堆中的对象
这时候就可以引入我们的深拷贝
深拷贝
拷贝的是对象 , 不是地址。 常见深拷贝方法 :
- 通过递归实现
- 引入第三方js库 (lodash等)
- 通过JSON.stringfy()方法
1.递归
const obj = {
age: 12,
info:[1,2,3],
data:{ length: 1 , width: 2}
}
const o = {}
function copy(oldObj,newObj){
for(let k in oldObj){
// 这里要注意一定要先判断 Array 再判断 Object!!! 可以自己想一下为什么
if(oldObj[k] instanceof Array){
newObj[k] = [] // 意思是 newObj.k = []
copy(newObj[k],oldObj[k]) //,然后将oldObj.k(一个数组)复制给newObj ,如果数组中每一项又是数组或者对象,那么会继续迭代,此时k分别对应数组的索引号或对象里的属性名,直到所有的值都完全拷贝
}else if(oldObj[k] instaceof Object){
newObj[k] = {}
copy(newObj[k],oldObj[k])
}
// 这里的k 是每次迭代拿到的属性名 , 第一次是age ,第二次是info ......
// 新对象是空对象,不能通过newObj.k的方式来将oldObj中的k属性赋值给newObj,所以必须用obj[k]
else{
newObj[k] = oldObj[k]
}
}
}
copy(o,obj)
2.引入lodash库
没什么好讲的,在npm里直接找文档
3.JSON.stringfy()方法
const obj = {
age: 12,
info:[1,2,3],
data:{ length: 1 , width: 2}
}
const string = JSON.stringfy(obj) //对象转 JSON字符串
const o = JSON.parse(string) //JSON字符串转对象,x相当于在栈中新建一个地址 ,堆中新开一个对象
以上~就是笔者对JS深浅拷贝的一些简单看法,如果读者在读这篇文章时发现了错误>_<或者是想到了更好的点子ヾ(^▽^*)可以通过QQ来联系笔者~感谢看到这里的各位

Comments NOTHING