对象深拷贝
用递归实现深拷贝,这里的函数做了bind
的处理,使其返回一个新的函数,至于值是对象的话会进行递归遍历,最后实现对象的深拷贝。
deepClone = (initalObj) => {
const obj = {};
if(typeof initalObj !== 'object'){
return initalObj
}
for (const key in initalObj) {
if (typeof initalObj[key] === 'object') {
//对数组特殊处理
if (Array.isArray(initalObj[key])) {
//用map方法返回新数组,将数组中的元素递归
obj[key] = initalObj[key].map(item => this.deepClone(item))
} else {
//递归返回新的对象
obj[key] = this.deepClone(initalObj[key]);
}
} else if (typeof initalObj[key] === 'function') {
//返回新函数
obj[key] = initalObj[key].bind(obj);
} else {
//基本类型直接返回
obj[key] = initalObj[key];
}
}
return obj;
}
const obj = {
a: 1,
b: {},
c: { d: {}, g: () => {} },
e: () =>{},
f: function () {}
}
const newObj = deepClone(obj);
newObj.a === obj.a //true
newObj.b === obj.b //false
newObj.c === obj .false //false
newObj.c.d === obj.c.d //false
newObj.c.g === obj.c.g //false
newObj.e === obj.e //false
newObj.f === obj.f //false
为什么需要深拷贝
理解一下引用类型
实际上JavaScript的对象是一个引用类型,那么可以这么理解const obj = {}
这个表达式,实际上可以把obj理解成内存中的指针,指向该对象的一个内存地址。我们知道当我们进行如下操作时
const newObj = obj
实际上我们只是把内存的指针附给了newObj
,好比我们把一栋房子的钥匙交给别人,而房子只有一栋的意思。所以理解这一点以后,我们就可以想象到,拷贝一个对象并不是那么简单的一件事
深拷贝做了什么
理解了引用类型以后,我们就可以想到。我们的对象里面也可以嵌套引用类型
const obj = {
a: 1,
b: {},
c: { d: {}, g: () => {} },
e: () =>{},
f: function () {}
}
那么实际上深拷贝需要做的事情就是,把对象中的引用类型全部复制一遍。复制一个引用类型,就需要在内存中新开一个空间,然后在把原对象有的东西都塞进去。那么这样的意思就是,换了内存地址和内存,但是内容还是那些内容。这里的话需要一张图来解答
我们想做到的深拷贝是这样的
而不是这样的
实际上这也叫浅拷贝,关于浅拷贝的方式有很多种,接下来会分享一些。那么关于深拷贝的做了什么相信大家也能直观的看见了。
对象浅拷贝
// 方法一:
const newObj = {...obj}
//方法二:
const newObj = Object.assgin({},obj)
//方法三:
const newObj = Object.creact({},obj)
emm,简单记住第一种方法就行,也是最简单的一种。
后话
其实深拷贝也有很多种,但是无非就是换一个方式去拷贝每一份对象而已。主要是掌握拷贝时候的思路,如果需要别的类型,比如需要保留对象的prototype,那么我们在拷贝每一份对象的使用Object.create
就可以。当然,如果有什么奇思妙想,也都可以添加,毕竟每个人的代码都有自己的思想
成功不在一朝一夕,我们都需要努力
热门评论
实际场景中,方法应该不需要进行深拷贝吧,公用也是貌似不存在什么问题,这边还是为了演示深拷贝做的特殊处理吧
1、数组的处理中,map要不要加return? 2、为什么要加函数处理,感觉多此一举?
能否不用递归的方式进行深拷贝