注意点:

  • Object.keysfor in 循环遍历的时候不能包含 Symbol 属性(ES6 解构运算符可以)
  • 各种类型的处理
  • 循环引用
let keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
// 浅克隆
function shallowClone(obj) {
  let type = _.toType(obj);
  Ctor = obj.constructor;
  // 对于SymFol/BigInt,直接用Object包裹一下
  if (/^(symbol|bigint)$/i.test(type)) return Object(obj);
  //对于正则/日期的处理
  if (/^(regexp|date)$/i.test(type)) return new Ctor(obj);
  //对于错误对象的处理
  if (/^error$/i.test(type)) return new Ctor(obj.message);
  // 对于函数
  if (/^function$/i.test(type)) {
    return function () {
      return obj.call(this, ...arguments);
    };
  }
  //数组或者对象
  if (/^(object|array)$/i.test(type)) {
    let keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
    let newObj = new Ctor();
    _.each(keys, (key) => {
      newObj[key] = obj[key];
    });
    return newObj;

    /* ES6 解构运算符可以处理Symbol属性
    return type === "array" ? [...obj] : { ...obj };
    */
  }
  return obj;
}
// 深克隆
function deepClone(obj, cache = new Set()) {
  let type = _.toType(obj);
  Ctor = obj.constructor;
  if (!/^(object|array)$/i.test(type)) {
    return shallowClone(obj);
  }

  // 防止循环引用
  if (cache.has(obj)) return obj;

  cache.add(obj);

  let keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
  let newObj = new Ctor();
  _.each(keys, (key) => {
    // 传入初始cache
    newObj[key] = deepClone(obj[key], cache);
  });
  return newObj;
}