编辑代码

// 浅拷贝
function shallwCopy(obj) {
    if (typeof obj !== 'object') return obj
    let newObj = obj instanceof Array ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) newObj[key] = obj[key];
    }
    return newObj;
};

// 简单深拷贝
function deepCopy(obj) {
    if (typeof obj !== 'object') return obj
    let newObj = obj instanceof Array ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) newObj[key] = deepCopy(obj[key]);
    }
    return newObj;
};

// 完善的深拷贝
// 1、额外开辟一个存储空间解决循环引用问题
// 2、WeakMap 解决使用 Map 会对内存造成非常大的额外消耗,而且我们需要手动清除 Map 的属性才能释放这块内存,
// 而 WeakMap 会帮我们巧妙化解这个问题,因为 WeakMap 的键是弱引用的,垃圾回收机制会自动帮我们回收
function deepCopy2(obj, weakMap = new WeakMap()) {
    // 如果是null或者undefined我就不进行拷贝操作
    if (obj === null) return obj;
    // Date,RegExp 等对象类型可以用构造函数和原始数据创建一个新对象返回
    if (obj instanceof Date) return new Date(obj);
    if (obj instanceof RegExp) return new RegExp(obj);
    // 不是对象的话,可能是简单类型或函数,不需要深拷贝,直接返回
    // 实际上克隆函数是没有实际应用场景的,两个对象使用一个在内存中处于同一个地址的函数也是没有任何问题的
    if (typeof obj !== "object") return obj;
    // 是对象的话就要进行深拷贝
    if (weakMap.get(obj)) return weakMap.get(obj);
    // 通过拿到constructor的方式来通用的获取array、object的初始化数据和[]和{}
    let newObj = new obj.constructor();
    // let newObj = obj instanceof Array ? [] : {}
    weakMap.set(obj, newObj);
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            // 实现一个递归拷贝
            newObj[key] = deepCopy2(obj[key], weakMap);
        }
    }
    return newObj;
}