浅拷贝,深拷贝

21 阅读2分钟
浅拷贝

浅拷贝就是对引用数据类型进行一层数据拷贝。

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属性执行同一块内存地址,浅拷贝并不会对引用数据类型的属性在进行拷贝。当引用数据只有一层的时候,用浅拷贝也可使实现深拷贝的效果。

  • 浅拷贝的方法
  1. Object.assign()
  2. 自己通过一些遍历的方法实现
深拷贝

实现方式

  1. 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" ] }

上面看着是可以将对象拷贝成功,但是当对象中存在函数是的时候,可以发现函数没有被拷贝。还存在别的问题。

image.png

  1. 一个简单的深拷贝。
这里是简单写的一个深拷贝

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 
}
  1. 使用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
  }
}