# 题目描述

请你完成一个函数 —— 实现对象参数的深拷贝并返回拷贝之后的新对象

要求:

  • 需要考虑函数,正则,日期和ES6新对象
  • 需要考虑循环引用问题

# 分析

  • 判断是否为对象是否为空,判断对象类型
  • 因为有函数,正则这些类型,所以要用正则来判断,如果是这些类型的对象,就直接返回一个新的该对象 —— 利用target.constructor来访问到父类的构造函数
  • 循环引用 —— 要使用map来存储<属性值,深拷贝对象>,如果该属性已经被深拷贝过了,就返回当前的深拷贝对象
  • 开始深拷贝 —— 递归

# 测试用例

function test() {
  const o1 = {
    name: "g",
    age: 18,
    o: { name: "o" },
    a: [1, 2],
    r: new RegExp(),
    d: new Date(),
  };
  o1.self = o1;
  const o2 = _completeDeepClone(o1);
  o1.name = "z";
  o1.age = 1;
  const judge =
    o1.name !== o2.name &&
    o1.age !== o2.age &&
    o1.o !== o2.o &&
    o1.a !== o2.a &&
    o1.r !== o2.r &&
    o1.d !== o2.d &&
    o1.self.self.self.self.self.self.self.self.self === o1.self &&
    o1.self !== o2.self;
  return judge;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 代码实现

function test() {
  const o1 = {
    name: "g",
    age: 18,
    o: { name: "o" },
    a: [1, 2],
    r: new RegExp(),
    d: new Date(),
  };
  o1.self = o1;
  const o2 = _completeDeepClone(o1);
  o1.name = "z";
  o1.age = 1;
  const judge =
    o1.name !== o2.name &&
    o1.age !== o2.age &&
    o1.o !== o2.o &&
    o1.a !== o2.a &&
    o1.r !== o2.r &&
    o1.d !== o2.d &&
    o1.self.self.self.self.self.self.self.self.self === o1.self &&
    o1.self !== o2.self;
  return judge;
};
const _completeDeepClone = (target, map = new Map()) => {
  if (!target || typeof target != "object") {
    return target;
  }
  let reg = /^(RegExp|Funtion|Data|Map|Set)$/;

  // constructor指向构造函数
  const constructor = target.constructor;
  if (reg.test(constructor.name)) {
    return new constructor(target);
  }

  // 防止递归调用一个属性
  if (map.get(target)) {
    return map.get(target);
  }

  const cloneTarget = Array.isArray(target) ? [] : {};
  map.set(target, cloneTarget);
  Object.keys(target).forEach((prop) => {
    if (target.hasOwnProperty(prop)) {
      // 递归拷贝
      cloneTarget[prop] =
        typeof target[prop] === "object"
          ? _completeDeepClone(target[prop], map)
          : target[prop];
    }
  });
  return cloneTarget;
};

console.log(test());
// true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57