• 判断类型,正则和日期直接返回新对象
  • 空或者非对象类型,直接返回原值
  • 考虑循环引用,判断如果hash中含有直接返回hash中的值
  • 新建一个相应的new obj.constructor加入hash
  • 遍历对象递归(普通key和key是symbol情况)
function deepClone(obj, hash = new WeakMap()) {
  if (obj instanceof RegExp) return new RegExp(obj)
  if (obj instanceof Date) return new Date(obj)
  if (obj === null || typeof obj !== 'object') return obj
  //循环引用的情况
  if (hash.has(obj)) {
    return hash.get(obj)
  }
  //new 一个相应的对象
  //obj为Array,相当于new Array()
  //obj为Object,相当于new Object()
  let constr = new obj.constructor()
  hash.set(obj, constr)
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      constr[key] = deepClone(obj[key], hash)
    }
  }
  //考虑symbol的情况
  let symbolObj = Object.getOwnPropertySymbols(obj)
  for (let i = 0; i < symbolObj.length; i++) {
    if (obj.hasOwnProperty(symbolObj[i])) {
      constr[symbolObj[i]] = deepClone(obj[symbolObj[i]], hash)
    }
  }
  return constr
}