浅拷贝
浅拷贝就是对引用数据类型进行一层数据拷贝。
let obj = {
name:"cj",
age:18,
hobbies:["swimming","singing","running"]
}
function clone(obj){
let newObj = {}
for(let key in obj){
newObj[key] = obj[key]
}
return newObj
}
let cloneObj = clone(obj)
console.log(cloneObj)
cloneObj.hobbies.pop()
console.log(obj)
- { "name": "cj", "age": 18, "hobbies": [ "swimming", "singing", "running" ] }
- { "name": "cj", "age": 18, "hobbies": [ "swimming", "singing" ] }
上述代码就是对引用对象的一层浅拷贝,我们通过打印可以发现当属性是引用数据类型的时候,我们在修改克隆的对象的hobbiles的时候,原对象的hobbies也改变。这是因为两者的hobbies属性执行同一块内存地址,浅拷贝并不会对引用数据类型的属性在进行拷贝。当引用数据只有一层的时候,用浅拷贝也可使实现深拷贝的效果。
- 浅拷贝的方法
- Object.assign()
- 自己通过一些遍历的方法实现
深拷贝
实现方式
- JSON.parse(JSON.stringify())(不推荐使用,无法处理函数,undefined,RegExp 等等类型的)
let obj = {
name:"cj",
age:18,
hobbies:["swimming","singing","running"]
}
let cloneObj = JSON.parse(JSON.stringify(obj))
console.log(cloneObj)
- { "name": "cj", "age": 18, "hobbies": [ "swimming", "singing", "running" ] }
上面看着是可以将对象拷贝成功,但是当对象中存在函数是的时候,可以发现函数没有被拷贝。还存在别的问题。
- 一个简单的深拷贝。
这里是简单写的一个深拷贝
function deepClone(option){
//首先应该判断是基本类型还是引用类型
if(typeof option !== 'object'){
//基本类型,直接返回
return option
}
//引用类型判断是对象还是数组
let flag = Array.isArray(option)
let clone = flag ? [] : {}
for(let key in option){
clone[key] = deepClone(option[key])
}
return clone
}
- 使用weakMap写深拷贝 上面的写法当中,如果设置如下的情况,会引发爆栈
let obj1 = {
name:"po",
hobbie:['a','b']
}
obj1.cs = obj1 //会引起爆栈
let obj2 = deepClone(obj1)
为了解决爆栈问题,我们可以使用map来解决循环引用引起的爆栈问题
之后我们可以进一步优化,使用WeakMap来替代Map,垃圾回收机制
if(typeof target === 'object'){
let isArray = Array.isArray(target)
let cloneTarget = isArray ? [] : {}
// 下面使用map可以解决爆栈的问题
if(map.get(target)){
// 说明有这个属性了
return map.get(target)
}
map.set(target,cloneTarget)
// 遍历target的属性赋给cloneTarget
for(let key in target){
cloneTarget[key] = deepClone(target[key],map) //注意这个地方要把map传入进去,不然爆栈问题依旧存在。
}
return cloneTarget
}else{
return target
}
}
function deepClone(target, map = new WeakMap()){
if(typeof target === 'object'){
let isArray = Array.isArray(target)
let cloneTarget = isArray ? [] : {}
// 下面使用map可以解决爆栈的问题
if(map.get(target)){
// 说明有这个属性了
return map.get(target)
}
map.set(target,cloneTarget)
// 遍历target的属性赋给cloneTarget
for(let key in target){
cloneTarget[key] = deepClone(target[key],map)
}
return cloneTarget
}else{
return target
}
}