# 深拷贝和浅拷贝

# 浅拷贝

实现浅拷贝的方法一般有2种, Object.assign...xx操作符




 








const obj = {
    name: 'chenying',
    age: 18,
    has: {
        vue: true
    }
}
const obj1 = {...obj}
obj1.name = 'ying'
console.log(obj) // { name: 'chenying', age: 18, has: { vue: true } }
console.log(obj1) // { name: 'ying', age: 18, has: { vue: true } }



 








const obj = {
    name: 'chenying',
    age: 18,
    has: {
        vue: true
    }
}
const obj1 = Object.assign(obj)
obj1.name = 'ying'
console.log(obj) // { name: 'ying', age: 18, has: { vue: true } }
console.log(obj1) // { name: 'ying', age: 18, has: { vue: true } }

# 深拷贝

最简单的深拷贝方法是使用JSON.parse(JSON.stringify(obj))




 








const obj = {
    name: 'chenying',
    age: 18,
    has: {
        vue: true
    }
}
const obj1 = JSON.parse(JSON.stringify(obj))
obj1.has.vue = false
console.log(obj) // { name: 'chenying', age: 18, has: { vue: true } }
console.log(obj1) // { name: 'chenying', age: 18, has: { vue: false } }

但是这个方法有点缺陷,例如

  • 会忽略 undefined
  • 会忽略 symbol
  • 会忽略 正则 日期
  • 不能序列化函数
  • 不能解决循环引用的对象

所以一般我们会自己实现一个深拷贝函数




 




















const obj = {
    name: 'chenying',
    age: 18,
    has: {
        vue: true
    }
}

function deepcopy(value) {
    if (value == null) { return value }
    if (value instanceof RegExp) { return new RegExp(value) }
    if (value instanceof Date) { return new Date(value) }
    if (typeof value !== 'object') { return value }
    let obj = new value.constructor() // 拿到[] 或者 {}
    for (let key in value) {
        obj[key] = deepcopy(value[key])
    }
    return obj
}
let obj1 = deepcopy(obj)
obj1.has.vue = false
console.log(obj) // { name: 'chenying', age: 18, has: { vue: true } }
console.log(obj1) //{ name: 'chenying', age: 18, has: { vue: false } }

但是这样写有一个缺陷,就是容易爆栈,例如我们这样调用




 

let obj2 = {}
obj2.x = obj2
let obj3 = deepcopy(obj2)
console.log(obj3)

那我们可以使用WeakMap的特性判断,如果之前这个值已经拷贝过了,就不需要在进行拷贝了




 














function deepcopy(value, hash = new WeakMap) {
    if (value == null) { return value }
    if (value instanceof RegExp) { return new RegExp(value) }
    if (value instanceof Date) { return new Date(value) }
    if (typeof value !== 'object') { return value }
    let obj = new value.constructor() // 拿到[] 或者 {}

    if (hash.get(value)) { // 如果hash表里面有这个值就不需要走拷贝了
        return hash.get(value)
    }
    hash.set(value, obj)

    for (let key in value) {
        obj[key] = deepcopy(value[key], hash)
    }
    return obj
}