Javascript实现深拷贝的三种方式

82 阅读1分钟

1.使用JSON.parse/stringify

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  return JSON.parse(JSON.stringify(obj));
}

这种方式虽然简单,但是会存在以下问题

  • 无法拷贝函数
  • 对象中存在循环引用,则会报错

2.使用MessageChannel

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return Promise.resolve(obj);
  }
  return new Promise((resolve) => {
    const { port1, port2 } = new MessageChannel();
    port2.onmessage = (e) => resolve(e.data);
    port1.postMessage(obj);
  });
}

这种方式也会存在一些问题

  • 拷贝函数会报错
  • 只能通过异步的方式调用

3.自己封装实现

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  const res = Array.isArray(obj) ? [] : {};
  for (const key in obj) {
    res[key] = deepClone(obj[key]);
  }
  return res;
}

以上封装还是无法解决对象循环引用报错的问题,下面我们新增一个Map来存储已经复制过的对象,存在则直接终止递归。

function deepClone(obj) {
  const copied = new WeakMap();
  const _clone = (_obj) => {
    if (_obj === null || typeof _obj !== "object") {
      return _obj;
    }
    if (copied.has(_obj)) {
      return _obj;
    }
    copied.set(_obj, true);
    const res = Array.isArray(_obj) ? [] : {};
    for (const key in _obj) {
      res[key] = _clone(_obj[key]);
    }
    return res;
  };

  return _clone(obj);
}