方法一
const deepClone = (a) => JSON.parse(JSON.stringify(a))
缺点:
- 不支持 undefined, 函数,Date, 正则 等数据
 - 不支持 循环引用
 
方法二
要对一个数据进行深拷贝,就需要对它的类型进行判断,JS中一共有8种数据类型, 其中复杂类型为 object, 其余7种为简单类型(string, number, undefined, null, boolean, bigint, symbol), 在 object 中又可以分为 Oject, Array, Function, Date, RegExp 等类,由此我们可以写成一个初始版本的深拷贝
- 如果传入的参数是基础类型则直接返回
 - 如果传入的参数是object则对类进行判断
- 如果是函数需要判断它是普通函数还是箭头函数
 - 如果是日期,则返回 
new Date(a - 0), 其中 a-0 得到的是时间戳 - 如果是正则,则返回 
new RegExp(a.source, a.flags) - 如果是数组,则将结果初始化为 
[] - 如果是对象,则将结果初始化为 
{} 
 接着遍历参数 a 的 key, 且用 hasOwnPropery 方法过滤 a 本身的 key, 对每个 key 递归调用深拷贝
function deepClone(a) {if (a instanceof Object) {let resultif (a instanceof Array) {result = []} else if (a instanceof Function) {if (a.prototype) {result = function(){return a.apply(this, arguments)}} else {result = (...args) => a.call(undefined, ...args)}} else if (a instanceof Date) {result = new Date(a - 0)} else if (a instanceof RegExp) {result = new RegExp(a.source, a.flags)} else {result = {}}for (let key in a) {if (a.hasOwnProperty(key)) {result[key] = deepClone(a[key])}}return result} else {return a}}
使用下面的代码测试,涉及到的类型都能进行深拷贝 ```javascript const a = { number: 1, bool: false, str: ‘hi’, empty1: undefined, empty2: null, array: [ {name: ‘jack’, age: 23}, {name: ‘rose’, age: 24} ], date: new Date(2000, 0, 1, 20, 30, 0), regexp: /.(j|t)sx/i, obj: {name: ‘jack’, age: 18}, f1: (a, b) => a + b, f2: function(a, b) {return a + b} }
const b = deepClone(a)
但是我们还没有考虑循环引用的情况,即当再添加一行下列代码,深拷贝就会报错了,会导致无限递归```javascripta.self = a
为了解决循环引用的问题,我们可以使用 Map 将进行过深拷贝的object类型存起来,在每次深拷贝object类型前都判断在 Map 中是否存在,若存在则直接返回 Map 中的值, 修改后的 deepClone 如下
function deepClone(a, map=new Map()) {if (a instanceof Object) {if (map.get(a)) {return map.get(a)}let resultif (a instanceof Array) {result = []} else if (a instanceof Function) {if (a.prototype) {result = function(){return a.apply(this, arguments)}} else {result = (...args) => a.call(undefined, ...args)}} else if (a instanceof Date) {result = new Date(a - 0)} else if (a instanceof RegExp) {result = new RegExp(a.source, a.flags)} else {result = {}}map.set(a, result)for (let key in a) {if (a.hasOwnProperty(key)) {result[key] = deepClone(a[key], map)}}return result} else {return a}}
在这里更加推荐使用 WeakMap,WeakMap只接受对象作为键名,且WeakMap的键名是对象的弱引用, 其所对应的对象可以被自动垃圾回收,当被垃圾回收时,WeakMap会自动移除该键值对。
