方法一

let newObj = JSON.parse(JSON.stringify(obj));

方法二

function deepClone (obj, hash = new WeakMap()) {
  // null 和 undefined 是不需要拷贝的
  if (obj == null) {
    return obj
  }
  if (obj instanceof RegExp) {
    return new RegExp(obj)
  }
  if (obj instanceof Date) {
    return new Date(obj)
  }

  // 函数是不需要拷贝的
  if (typeof obj != 'object') return obj

  // 避免陷入死循环
  if (hash.get(obj)) return hash.get(obj)

  let cloneObj = new obj.constructor()
  hash.set(obj, cloneObj)

  // for-in循环 会遍历当前对象上的属性和__proto__上的属性
  for (let key in obj) {
    // 不拷贝 对象的__proto__上的属性
    if (obj.hasOwnProperty(key)) {
      cloneObj[key] = deepClone(obj[key], hash)
    }
  }
  return cloneObj
}
// 拷贝目标
let obj = {
  name: 'myDog',
  age: 12,
  boo: true,
  n: null,
  m: undefined,
  sy: Symbol('sym'),
  big: 10n,
  child: {
    ele: 'body',
    x: 100
  },
  arr: [10, 20, 30],
  reg: /^\d+$/,
  fn: function () {
    console.log(this.name)
  },
  time: new Date(),
  err: new Error()
}

obj.obj = obj
let n = deepClone(obj)
n.child.ele = 'abc'
console.log(n)
console.log(obj)

控制台结果

学习笔记之手写实现 js 中的深拷贝_字符串

写在最后

方法一的弊端
  1. obj.obj = obj;会导致死循环,栈溢出
  2. BigInt类型报错:BigInt Uncaught TypeError: Do not know how to serialize a BigInt
  3. 属性值类型为 symbol/undefined/function 会丢失
  4. 信息不准确,例如:正则->空对象 Error 对象->空对象 日期对象->字符串 ...