基础版:

function deepClone(obj) {
  // 基本类型直接返回
  if (obj === null || typeof obj !== 'object') return obj

  // 数组用 [],对象用 {}
  const result = Array.isArray(obj) ? [] : {}

  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {      // 只拷贝自身属性,排除原型链
      result[key] = deepClone(obj[key]) // 递归拷贝
    }
  }
  return result
}

基础版处理大部分的深拷贝都是可以的,但是如果碰到DATE类型RegExp类型以及自身循环引用的话就会报错空对象以及陷入死循环

升级版:

function deepClone(obj, map = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj
  // ① 处理循环引用:已经拷过就直接返回
  if (map.has(obj)) return map.get(obj)
  // ② 处理特殊对象
  if (obj instanceof Date) return new Date(obj)
  if (obj instanceof RegExp) return new RegExp(obj)
  // ③ 创建新对象/数组
  const result = Array.isArray(obj) ? [] : {}
  map.set(obj, result)   // ⭐ 记录映射,供循环引用使用
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      result[key] = deepClone(obj[key], map)
    }
  }
  return result
}

如果是date和regexp类型就特殊判断世界用对应类型的值直接返回。

如果是自引用那就用map的键值对来判断是不是之前有过这个键的存在从而直接返回拦截循环

当然还有一个原生的深拷贝(浏览器或者Nodejs自带的,看环境,webapi)

const clone = structuredClone(obj)

还有一个json.Prase(json.stringify)也是深拷贝,不过灵活度和覆盖度最低