Skip to content
导航栏

深拷贝

1. 简易版深拷贝

js
/**
 * 简易深拷贝实现
 * @type {symbol}
 *
 *   缺点: 不能拷贝函数和Symbol值, 不能解决循环引用
 */
const s1 = Symbol()
const s2 = Symbol()

const obj = {
    name: "hzy",
    friend: {
        name: 'kobe'
    },
    foo: function () {
        console.log(this.name)
    },
    [s1]: 'abc',
    s2: s2
}

// obj.inner = obj
// 上方这行代码会报错,循环引用报错

const info = JSON.parse((JSON.stringify(obj)))

console.log(info)
console.log(info === obj)
obj.friend.name = 'nice'
console.log(obj)

2. 完整版深拷贝

  • 使用map来解决循环引用的问题
  • 使用递归来解决对象的嵌套问题
  • 判断数据类型为Sybmol, Set, Map, Function的情况
js
const s1 = Symbol()
const s2 = Symbol()
function isObject(value) {
    const valueType = typeof value;
    return value !== null && (valueType === 'object' || valueType === 'function')
}

 function deepClone(originValue, map = new WeakMap()) {
     // 判断是否是一个Set类型
     if(originValue instanceof Set) {
         return new Set([...originValue])
     }

     // 判断是否是一个Map类型
     if (originValue instanceof Map) {
         return new Map([...originValue])
     }

     // 判断如果是Symbol的value, 那么创建一个新的Symbol
     if (typeof originValue === 'symbol') {
         return Symbol(originValue.description)
     }

     // 判断如果是函数类型, 那么直接使用同一个函数
     if(typeof originValue === 'function') {
        return originValue
     }

     // 判断传入originValue是否是一个对象类型
     if(!isObject(originValue)) {
         return originValue
     }

     if(map.has(originValue)) {
         return map.get(originValue)
     }

    // 判断传入的对象是数组, 还是对象
    const newObject = Array.isArray(originValue) ? [] : {}
    map.set(originValue, newObject)
    for(const key in originValue) {
        newObject[key] = deepClone(originValue[key], map)
    }

    // 对Symbol的key进行特殊的处理
     const symbolKeys = Object.getOwnPropertySymbols(originValue)
     for(const sKeys of symbolKeys) {
         newObject[sKeys] = deepClone(originValue[sKeys], map)
     }

    return newObject
}

// 测试代码
const obj = {
    name: "hzy",
    age: 18,
    friend: {
        name: "james",
        address: {
            city: "广州"
        }
    },
    // 数组类型
    hobbies: ["abc", "cba", "nba"],
    // 函数类型
    foo: function(m, n) {
        console.log("foo function")
        console.log("100代码逻辑")
        return 123
    },
    // Symbol作为key和value
    [s1]: "abc",
    s2: s2,
    // Set/Map
    set: new Set(["aaa", "bbb", "ccc"]),
    map: new Map([["aaa", "abc"], ["bbb", "cba"]])
}

const newObj  = deepClone(obj)
console.log(newObj === obj)

obj.friend.name = 'kobe'
obj.friend.address.city = '成都'

console.log(newObj)