关于深浅 copy

深拷贝

structuredClone

参考这篇 (opens in a new tab)MDN (opens in a new tab)

是 JS built-in 的方法,能够做到真正的深拷贝

和其他方法的比较:

  • JSON.parse/JSON.stringify:太 tricky 了,一些对象被 string 之后再转回去就有问题了(比如 Date)
  • lodash/deepClone:js 实现,性能开销肯定比原生大,第三方库代码体积大

有哪些对象是不能被 clone 的:(会抛 DataCloneError

  • functions
  • DOM nodes
  • getter & setter
  • Object prototypes:比如一个 class

可以被 clone 的类型 (opens in a new tab)

兼容性:

  • 算是比较新的特性(chrome 98、ff 94)
  • node 要 17 才支持
  • polyfill 的话,core-js 支持

手写代码(weakmap)

一个比较完整的深拷贝函数,需要同时考虑对象和数组,考虑循环引用:

function deepCopy(obj, map = new WeakMap()) {
  if (typeof obj === "object") {
    const newObj = Array.isArray(obj) ? [] : {};
    if (map.has(obj)) {
      // 如果这个对象已经被引用了 有循环引用 直接返回
      return map.get(obj);
    }
    map.set(obj, newObj);
    for (let key in obj) {
      newObj[key] = deepCopy(obj[key], map);
    }
    return newObj;
  } else {
    return obj; // 不是引用类型的直接返回一份 因为形参已经是 copy 了
  }
}
// 测试一下
let aa = {
  abc: 123,
  bbc: { ddd: 433 },
};
aa.eee = aa;
let bb = deepCopy(aa);
aa.eee = 444444;
bb.bbc.ddd = 4444;
console.log(bb.eee);
console.log(aa.eee);

浅拷贝

有多种方法,解构展开、assign、create、...当然里面的引用指针也被 copy 了一份一样的地址

const shallowCopy = { ...simpleEvent };
const shallowCopy = Object.assign({}, obj);
const shallowCopy = Object.create(simpleEvent);