手写深拷贝

90 阅读1分钟

众所周知: 深拷贝的实现方案有很多 最简单的 莫过于 JSON.stringify 和 JSON.parse 要注意的是记得用 try catch

其次便是使用 lodash, Radash 的库等等

方案三就是自己手写一个 深拷贝

首先定义一下测试用例:

const obj = {
    a: 1,
    b: 'string',
    c: null,
    d: undefined,
    e: new Date(),
    f: Symbol(),
    g: {
       a: 2,
       b: 'string-2',
       c: null
    },
    h: function () { return 123; },
    m: [1, 2, 3]
    i: [1, 2, undefined, null, 'string']
    j: [1, 2, {a: 3, b: 'string-3', c: null}]
}
// 外加循环引用
obj.obj = obj

首先,先不管特殊类型和循环引用

    const deepClone = (obj) => {
        if (!obj) return obj;
        if (typeof obj != "object") return obj;
        const targetObj = object.create(obj);
        for(let cur in obj) {
            targetObj[cur] = deepClone(obj[cur])
        }
        return targetObj;
    }

现在我们来解决一下特殊类型的干扰

    const deepClone = (obj) => {
        if (!obj) return obj;
        if (obj instanceof Date) return new Date(obj);
        if (typeof obj != "object") return obj;
        const targetObj = new obj.constructor();
        for(let cur in obj) {
            targetObj[cur] = deepClone(obj[cur])
        }
        return targetObj;
    }

接下来通过 map 来限制循环引用,方案类似于记忆化 + 深搜剪枝

    const deepClone = (obj, map = new WeakMap()) => {
        if (!obj) return obj;
        if (obj instanceof Date) return new Date(obj);
        if (typeof obj != "object") return obj;
        // 剪枝优化,防止无限递归爆栈
        if (map.get(obj)) return map.get(obj);
        const targetObj = new obj.constructor();
        map.set(obj, targetObj);
        for(let cur in obj) {
            if(obj.hasOwnProperty(key)) {
                  targetObj[cur] = deepClone(obj[cur])   
            }
        }
        return targetObj;
    }