深度克隆,面试官想要的版本

59 阅读2分钟

网上有太多的深度克隆版本了,看得眼花缭乱。如何才能清晰的给面试官留下一个完美印象的版本。我想这一个案例可以一试

const target = {
  field1: 1,
  field2: null,
  field3: {
    child: 'child'
  },
  field4: [2, 4, 8],
  field5: new Set([1, '123', null, {name: 123}, undefined]),
  field6: new Map([["name", {name: 123}]]),
  say() {
    console.log(this.name)
  },
  field7: new Date("2001-12-1"),
  field8: new RegExp(/123/),

};
// 模拟一下有循环引用的使用的情况
target.target = target

// 判断一下是否为基础类型,或者应用类型
function isNormal(target) {
  if (target === null) {
    return true
  }
  return typeof target !== "object"
}
// 针对不同的数据类型,应该有不同的克隆方法
function cloneMap(target, set) {
  let map = new Map();
  for (let [key, val] of target.entries()) {
    map.set(key, deepClone(val, set))
  }
  return map
}

function cloneSet(target, set) {
  let mySet = new Set();
  for (let val of target) {
    mySet.add(deepClone(val, set))
  }
  return mySet
}

function cloneArray(target, set) {
  let arr = [];
  for (let val of target) {
    arr.push(deepClone(val, set))
  }
  return arr
}

function cloneObject(target, set) {
  let res = {};
  for (let key in target) {
    res[key] = deepClone(target[key], set)
  }
  return res
}

function cloneDate(target, set) {
  return new Date(target)
}

function cloneRegExp(target, set) {
  return new RegExp(target)
}
// set数据结构用来保存已经克隆过的对象,如果已经克隆过,则直接从set中去除克隆后的对象
function deepClone(target, set = new Set()) {
  if (isNormal(target)) {
    return target
  }
  if (set.has(target)) {
    return target
  }
  set.add(target)
  // 更具引用数据的类型,采用不同的克隆方法,而且避免修改了原型链,我们直接用最原始的方法判断数据类型
  switch (Object.prototype.toString.call(target)) {
    // 这里需要对所有不同类型的引用类型进行判断。如果所有特殊案例都不符合,则用基本的对象类型。
    case "[object Map]":
      return cloneMap(target, set);
    case "[object Set]":
      return cloneSet(target, set)
    case "[object Array]":
      return cloneArray(target, set)
    case "[object Date]":
      return cloneDate(target, set)
    case "[object RegExp]":
      return cloneRegExp(target, set)
    default:
      return cloneObject(target, set)
  }
}
console.log(deepClone(target))
console.log(new Map().toString())