浅拷贝

浅拷贝,就是只拷贝对象的引用,而不深层次的拷贝对象的值,多个对象指向堆内存中的同一对象,任何一个修改都会使得所有对象的值修改,因为它们公用一条数据。

深拷贝

深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突。

深拷贝的实现

使用JSON.parse(JSON.stringify(xx))

弊端:

  1. 拷贝Date对象,会变成string字符串。
  2. 拷贝RegExpError对象,序列化之后会变成空对象。
  3. 拷贝函数、undefined,序列化之后会丢失。
  4. 拷贝NaN、Infinity,序列化之后值会变成null。
  5. JSON.stringify只能序列化可枚举的对象属性,如果对象是由构造函数生成,序列化之后则会丢失对象的constructor属性。
function Person(name) {
  this.name = name;
}
const liai = new Person('liai');
const a = [1, 2, 3]
const b = { arr: a, date: new Date(), reg: /abc/, err: new Error(), fun() { console.log(123) }, un: undefined, NaN: NaN, infinity: Infinity, liai }
const c = JSON.parse(JSON.stringify(b))
console.log(c);
console.log(c.liai.constructor);
console.log(liai.constructor);

4M7O0g.pngopen in new window

Object.assign(target, ...source)

弊端:无法拷贝对象引用。

最终实现

const deepCopy = function (obj, cache = new WeakMap()) {
    if (!obj instanceof Object) return obj;

    // 返回循环引用
    if (cache.has(obj)) {
      console.log(cache.get(obj));
      console.log('---------');
      return cache.get(obj);
    }

    // 支持函数
    if (obj instanceof Function) {
      return function () {
        return obj.apply(this, arguments);
      };
    }
    // 支持日期
    if (obj instanceof Date) return new Date(obj);
    // 支持正则
    if (obj instanceof RegExp) return new RegExp(obj.source, obj.flags);

    const res = Array.isArray(obj) ? [] : {};
    cache.set(obj, res);

    Object.keys(obj).forEach((key) => {
      if (obj[key] instanceof Object) {
        res[key] = deepCopy(obj[key], cache);
      } else {
        res[key] = obj[key];
      }
    });
    return res;
  };
上次更新:
贡献者: chenzilin