手写实现深浅拷贝

129 阅读2分钟

「这是我参与2022首次更文挑战的第4天,活动详情查看:2022首次更文挑战」。

首先如果你弄不清楚什么是深浅拷贝,你需要先弄清楚。下面我们实现一个简单的浅拷贝。

浅拷贝手写实现,我们需要判断赋值对象的类型,如果是基础类型就直接返回,引用类型的话,null直接返回null,再判断是数组还是对象,然后for in循环去赋值。

一、浅拷贝的实现

function clone(target) {
  if (target === null) { // null也是对象类型
    return target
  }
  if (typeof target === 'object') {
    let cloneTarget = Array.isArray(target) ? [] : {}
    for (const key in target) {
      if (Object.hasOwnProperty.call(target, key)) {
        cloneTarget[key] = target[key]
      }
    }
    return cloneTarget
  }
  return target
}

二、深拷贝的实现

对于深拷贝,我们知道对于对象里面属性还是对象,这样可能一直嵌套下去,所以我们需要用到递归,对于上面的函数,我们只需要修改一点(顺便我们将方法名改为deepClone)。

cloneTarget[key] = deepClone(target[key])

如果你在面试中实现了上面的方法,面试官可能会问你循环引用怎么解决呢? 好,我们先弄清楚什么是循环引用,我们先看一个例子:

const target = {
  a: {
    b: 111
  }
}

target.t = target
deepClone(target)

我们会发现这时候,报错了,死循环了,你可以再deepClone中打印target看看;这样我们就清楚了,一个对象的属性调用自己就出现了循环引用的情况。

我们怎么解决呢?就是需要找一个地方,把拷贝过的存储起来,在循环赋值的时候,我们先去判断,是不是已经拷贝过,如果是,就直接返回这个存储的对象即可,我们这里采用WeakMap

function deepClone(target, weakMap = new WeakMap()) {
  if (target === null) { // null也是对象类型
    return target
  }
  if (typeof target === 'object') {
    let cloneTarget = Array.isArray(target) ? [] : {}
    if (weakMap.has(target)) {
        return weakMap.get(target)
    }
    weakMap.set(target, cloneTarget)
    for (const key in target) {
      if (Object.hasOwnProperty.call(target, key)) {
        cloneTarget[key] = deepClone(target[key], weakMap)
      }
    }
    return cloneTarget
  }
  return target
}

当你这样写,面试官一定会问你WeakMap,所以你一定得弄清楚WeakMap

下面我们看一个例子:

    const target = {
      a: {
        b: 111,
        s: Symbol(),
        [Symbol()]: 'symbol1',
        date: new Date('2022-12-12'),
        reg: new RegExp('abc')
      }
    }

    target.t = target
    target1 = deepClone(target)
    target.t.a.b = 999
    target.t.a.date = new Date('2021-12-1')
    console.log(111, target, target1)

image.png 我们可以看到对于symbol类型的keyfor in循环是不行的,我们采用Reflect.ownKeys去解决。 image.png 对于RegExpDate等类型的处理,大家可以看看这篇文章juejin.cn/post/684490…