/*
 * @Descripttion: HJ
 * @Company: 思宏科技
 * @version: v1.0
 * @Author: HJ
 * @Date: 2021-03-12 12:20:49
 * @LastEditors: HJ
 * @LastEditTime: 2021-03-12 14:18:39
 */

// 在对象上调用toString方法之后不同的数据会得到不同的字符串

// 可以继续遍历的类型
const mapTag = "[object Map]";
const setTag = "[object Set]";
const arrayTag = "[object Array]";
const objectTag = "[object Object]";
const argsTag = "[object Arguments]";

// 不可继续遍历的类型
const boolTag = "[object Boolean]";
const dateTag = "[object Date]";
const numberTag = "[object Number]";
const stringTag = "[object String]";
const symbolTag = "[object Symbol]";
const errorTag = "[object Error]";
const regexpTag = "[object RegExp]";
const funcTag = "[object Function]";

const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];

// 更快的迭代数组的forEach方法
function forEach(array, iteratee) {
  let index = -1;
  const length = array.length;
  while (++index < length) {
    iteratee(array[index], index);
  }
  return array;
}

// 是否是对象
function isObject(target) {
  const type = typeof target;
  return target !== null && (type === "object" || type === "function");
}

// 获取类型
function getType(target) {
  return Object.prototype.toString.call(target);
}

// 初始化被克隆的对象-用要拷贝对象的constructor新创建一个对象
function getInit(target) {
  const Ctor = target.constructor;
  return new Ctor();
}

// 克隆Symbol类型
function cloneSymbol(targe) {
  return Object(Symbol.prototype.valueOf.call(targe));
}

// 克隆一个正则
function cloneReg(targe) {
  const reFlags = /\w*$/;
  const result = new targe.constructor(targe.source, reFlags.exec(targe));
  result.lastIndex = targe.lastIndex;
  return result;
}

// 克隆一个函数
// function cloneFunction(func) {
//   const bodyReg = /(?<={)(.|\n)+(?=})/m;
//   const paramReg = /(?<=\().+(?=\)\s+{)/;
//   const funcString = func.toString();
//   // 通过是否含有prototype判断是否是箭头函数
//   if (func.prototype) {
//     const param = paramReg.exec(funcString);
//     const body = bodyReg.exec(funcString);
//     if (body) {
//       if (param) {
//         const paramArr = param[0].split(",");
//         return new Function(...paramArr, body[0]);
//       } else {
//         return new Function(body[0]);
//       }
//     } else {
//       return null;
//     }
//   } else {
//     return eval(funcString);
//   }
// }

function cloneOtherType(targe, type) {
  const Ctor = targe.constructor;
  switch (type) {
    case boolTag:
    case numberTag:
    case stringTag:
    case errorTag:
    case dateTag:
      return new Ctor(targe);
    case regexpTag:
      return cloneReg(targe);
    case symbolTag:
      return cloneSymbol(targe);
    // case funcTag:
    //   return cloneFunction(targe);
    default:
      return null;
  }
}

export function clone(target, map = new WeakMap()) {
  // 对于基本类型直接返回自身即可
  if (!isObject(target)) {
    return target;
  }

  // 获得要复制的对象类型，不同类型的对象复制方法不同
  const type = getType(target);
  let cloneTarget;
  if (deepTag.includes(type)) {
    cloneTarget = getInit(target, type);
  } else {
    return cloneOtherType(target, type);
  }

  // 防止循环引用
  if (map.get(target)) {
    return map.get(target);
  }
  map.set(target, cloneTarget);

  // 克隆set
  if (type === setTag) {
    target.forEach((value) => {
      cloneTarget.add(clone(value, map));
    });
    return cloneTarget;
  }

  // 克隆map
  if (type === mapTag) {
    target.forEach((value, key) => {
      cloneTarget.set(key, clone(value, map));
    });
    return cloneTarget;
  }

  // 克隆对象和数组
  const keys = type === arrayTag ? undefined : Object.keys(target);
  forEach(keys || target, (value, key) => {
    if (keys) {
      key = value;
    }
    cloneTarget[key] = clone(target[key], map);
  });

  return cloneTarget;
}


