JavaScript深拷贝

JavaScript深拷贝

function deepCloneDFS(origin, map = new Map()) {
  // 循环引用检测
  if (map.get(origin)) {
    return origin;
  }
  // 把对象作为键名
  map.set(origin, true)

  // 命中策略
  let constructorType = Object.prototype.toString.call(origin);
  let fn = strategy[constructorType];
  if (fn) {
    return fn(origin, map);
  }

  // 没有命中策略的,使用自身的构造函数重建一个
  const constructor = origin.constructor;
  return new constructor(origin);
}

// 策略
var strategy = {
  '[object Number]': function (origin) { return origin },
  '[object String]': function (origin) { return origin },
  '[object Boolean]': function (origin) { return origin },
  '[object Null]': function (origin) { return origin },
  '[object Undefined]': function (origin) { return origin },

  '[object Symbol]': function (origin) {
    return new Object(Symbol.prototype.valueOf.call(origin));
  },
  '[object BigInt]': function (origin) { return origin },

  '[object Function]': function (origin) {
    // 箭头函数直接返回
    if (!origin.prototype) {
      return new Function(origin.toString());
    }
    // 普通函数需要正则处理处理
    const bodyReg = /(?<={)(.|\n)+(?=})/m;
    const paramReg = /(?<=\().+(?=\)\s+{)/;
    const funcString = origin.toString();
    // 分别匹配 函数参数 和 函数体
    const param = paramReg.exec(funcString);
    const body = bodyReg.exec(funcString);
    if(!body) return null;
    if (param) {
      const paramArr = param[0].split(',');
      return new Function(...paramArr, body[0]);
    } else {
      return new Function(body[0]);
    }
  },

  // Map 得小心它的 key 和 value 都可能是个对象需要深拷贝
  '[object Map]': function (origin, map) {
    let result = new Map();
    origin.forEach((item, key) => {
      result.set(deepCloneDFS(key, map), deepCloneDFS(item, map));
    })
    return result;
  },

  '[object Set]': function (origin, map) {
    let result = new Set();
    origin.forEach((item) => {
      result.add(deepCloneDFS(item, map));
    });
    return result;
  },

  '[object Array]': function(origin, map) {
    let result = [];
    origin.forEach((item, index) => {
      result[index] = deepCloneDFS(item, map);
    });
    return result;
  },
  '[object Object]': function(origin, map) {
    let result = {};
    Object.keys(origin).forEach(key => {
      result[key] = deepCloneDFS(origin[key], map);
    });
    return result;
  }
}