手写深拷贝函数

我们在面试的时候,可能会被要求实现一个深拷贝。

深拷贝

这其实是一个高频的手写题:

// 利用 WeakMap 解决循环引用
let map = new WeakMap()
function deepClone(obj) {
  if(obj instanceof Object) {
    if(map.has(obj)) {
      return map.get(obj)
    }
    let newObj
    if(obj instanceof Array) {
      newObj = []
    } else if(obj instanceof Function) {
      newObj = function() {
        return obj.apply(this, arguments)
      }
    } else if(obj instanceof RegExp) {
      // 拼接正则
      newobj = new RegExp(obj.source, obj.flags)
    } else if(obj instanceof Date) {
      newObj = new Date(obj)
    } else {
      newObj = {}
    }
    // 克隆一份对象出来
    let desc = Object.getOwnPropertyDescriptors(obj)
    let clone = Object.create(Object.getPrototypeOf(obj), desc)
    map.set(obj, clone)
    for(let key in obj) {
      if(obj.hasOwnProperty(key)) {
        newObj[key] = deepClone(obj[key])
      }
    }
    return newObj
  }
  return obj
}

以上代码解决了常见类型的copy和循环引用的问题。

不过瑕疵还是有的,例如递归肯定会存在爆栈的问题,因为执行栈的大小是有限制的,到一定数量栈就会爆掉。

如果遇到这种问题,解决之道就是:用遍历的方式来改写递归。也就是如何写层序遍历(BFS)的问题了,只需要通过数组来模拟执行栈就能解决。

在面试的时候如果被要求手写深拷贝,能写出上面的代码已经完全够了,剩下的能口述思路基本上这道题就能拿到高分。