SOURCE

let {log} = console;
let originObj = {x: {x1: 1, y1: 2}, y: 3};

Object.defineProperty(originObj,"innumberable",{
    enumerable:false,
    value:"innumberable"
})

function copyObj(obj,targetObj={}){
    return Object.assign(targetObj,obj)
}
console.log(copyObj(originObj))

function copyObj2(obj){
    return {...obj}
}
log(copyObj2(originObj))

let originArr = [{x:1},2,3]
function copyArr(arr){
    return arr.slice(0)
}

let copya = copyArr(originArr);
originArr[0].x = 22;
originArr[1] = 99;
log(copya)

function copyArr2(arr){
    return arr.concat();
}
let copya1 = copyArr2(originArr)
originArr[0].x = 999;
originArr[1] = 0;
log(copya1)

function shallowClone(target){
    if(typeof target === "object" && typeof target !== null){
        let cloneTarget = Array.isArray(target)?[]:{};
        for(let prop in target){
            if(target.hasOwnProperty(prop)){
                cloneTarget[prop] = target[prop]
            }
        }
        return cloneTarget;
    }else{
        return target
    }
}
log(shallowClone(originObj))

function deepClone(target){
    return JSON.parse(JSON.stringify(target));
}
let dp1 = deepClone(originObj);
originObj.x.x1 = 99;
originObj.y = 999
log(dp1)
let dp2 = deepClone(originArr);
originArr[0].x = 33;
originArr[1] = 88;
log(dp2)

/**
 * JSON.parse(JSON.stringify()) 的缺点
 * 1. 如果键值对的值是函数、undefined或者symbol,那么经过stringify序列化就会消失
 * 2. Date()引用对象的值会变成字符串
 * 3. RegExp正则,值会变为空对象 {}
 * 4. 如果键值对值是NaN、Infinity、-Infinity,经过序列化会变成null
 * 5. 不能拷贝对象的原型链
 * 6. 不能拷贝对象的循环引用 obj[a] = obj
 * 7. 不能拷贝不可枚举值
 */

const wm1 = new WeakMap(),
      wm2 = new WeakMap(),
      wm3 = new WeakMap();
const o1 = {},
      o2 = function() {},
      o3 = window;
wm1.set(o1, 37);
wm1.set(o2, 'azerty');
wm2.set(o1, o2); // value 可以是任意值,包括一个对象或一个函数
log(wm1)
log(wm2)


const isComplexDataType = obj=>(typeof obj ==="object" || typeof obj === "function") && (obj !==null);
function deepClone1(obj,hash = new WeakMap()){
    if(obj.constructor === Date){
        return new Date(obj)
    }
    if(obj.constructor === RegExp){
        return new RegExp(obj);
    }
    // 循环引用
    if(hash.has(obj)){
        return hash.get(obj)
    }
    // getOwnPropertyDescriptors 获取的是对象的所有描述,大对象
    let allDesc = Object.getOwnPropertyDescriptors(obj);
    log(allDesc,'----allDesc')
    let cloneObj = Object.create(Object.getPrototypeOf(obj),allDesc);
    hash.set(obj,cloneObj);
    log(hash,"---hash")
    log(Reflect.ownKeys(obj))
    for(let key of Reflect.ownKeys(obj)){
        cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== "function")?deepClone1(obj[key],hash):obj[key];
    }
    return cloneObj;
}
let obj = {
  num: 0,
  str: '',
  boolean: true,
  unf: undefined,
  nul: null,
  obj: { name: '我是一个对象', id: 1 },
  arr: [0, 1, 2],
  func: function () { console.log('我是一个函数') },
  date: new Date(0),
  reg: new RegExp('/我是一个正则/ig'),
  [Symbol('1')]: 1,
};
let dp3 = deepClone1(obj);
log(dp3)

console 命令行工具 X clear

                    
>
console