深拷贝/克隆 Deep Clone

251 阅读1分钟
function deepClone(origin, hashMap = new WeakMap()) {
    //undefined, null, 原始值, Func => 直接返回
    if (origin == undefined || typeof origin !== 'object'){
        return origin;
    }
    //分析包装类型
    const type = Object.prototype.toString.call(origin).slice(8, -1);
    switch (type) {
        // {}对象 单独处理
        case 'Map':
        case 'Set':
        case 'Object':
            break;
        //一般origin对象最外层为[],{}
        case 'Array':
             return Array.prototype.valueOf.call(origin);
        //普通包装类
        default: 
            //原对象构造
            return Object.prototype.valueOf.call(origin);
    }
    //  防止循环引用
    const hashKey = hashMap.get(origin);
    if (hashKey) {return hashKey;}
    const target = new origin.constructor();
    hashMap.set(origin, target);
    
    if (type === 'Map') {
        origin.forEach((item, key) => {
            target.set(deepClone(item, hashMap), deepClone(key, hashMap));
        })
    }
    if (type === 'Set') {
        origin.forEach((item) => {
            target.add(deepClone(item, hashMap));
        })
    }
    for (let k in origin) {
        if (origin.hasOwnProperty(k)) {
            target[k] = deepClone(origin[k], hashMap);
        }
    }
    return target;
}
// Test Example
const map = new Map();
map.set('key', 'value');
map.set('Li', 'codes');

const set1 = new Set();
set1.add('ConardLi');
set1.add('code');

const objA = {
    op: Boolean(undefined),
    field1: 1,
    field2: undefined,
    field3: {
        child: 'child',
        abd: {
            cd: {
                lsl: '2'
            }
        }
    },
    field4: [2, 4, 8, {
        what: '99',
        sks: {
            l: ['l']
        }
    }],
    empty: null,
    map,
    set1,
    bool: new Boolean(true),
    num: new Number(2),
    str: new String(2),
    symbol: Object(Symbol(1)),
    symbol2: Symbol(2),
    date: new Date(),
    reg: /\d+/,
    error: new Error(),
    func1: () => {
        console.log('code秘密花园');
    },
    func2: function (a, b) {
        return a + b;
    },
    body: document.body
  };
  
  const objB = deepClone(objA);
  console.log(objA === objB); // 打印 false
  console.log(objA, objB); // 对象内容一样