深拷贝对象

# 深拷贝对象

第一种: JSON.parse(JSON.stringify(obj))

const obj = {
  a: {
    b: 1,
    c: {
      d: 2
    }
  }
}
const deepObj = JSON.parse(JSON.stringify(obj))
deepObj.a.b = 3
console.log(obj.a.b)  // 1
console.log(deepObj.a.b)  // 3
1
2
3
4
5
6
7
8
9
10
11
12

第二种: deepClone, 就是将以下类型进行复制, 基本类型可直接赋值, 但是以下类型需要特殊处理:

date, regexp, function, symbol, map, set, object, array

点击查看代码
function getType(target) {
  return Object.prototype.toString
    .call(target)
    .slice(8, -1)
    .toLowerCase();
}

/**
 * 深复制
 * @param {object} obj 
 * @param {object} clonedObj 
 * @returns {object}
 */
const deepClone = (obj, clonedObj = new WeakMap()) => {
  if (obj === null || typeof obj !== 'object') return obj
  if (clonedObj.has(obj)) {
    return clonedObj.get(obj)
  }

  const type = getType(obj)
  let clone;

  if (type === 'date') {
    clone = new Date(obj.getTime())
  } else if (type === 'regexp') {
    clone = new RegExp(obj)
  } else if (type === 'function') {
    clone = function() {
      return obj.apply(this, arguments)
    }
  } else if (type === 'symbol') {
    clone = Object(Symbol.prototype.valueOf.call(obj))
  } else if (type === 'map') {
    clone = new Map()
    for (const [key, value] of obj) {
      clone.set(deepClone(key, clonedObj), deepClone(value, clonedObj))
    }
  } else if (type === 'set') {
    clone = new Set()
    for (const value of obj) {
      clone.add(deepClone(value, clonedObj))
    }
  } else if (type === 'object' || type === 'array') {
    clone = new obj.constructor()
    clonedObj.set(obj, clone)
    // fix: Reflect.ownKeys 可以遍历拿到 symbol 的 key
    // refs: https://es6.ruanyifeng.com/#docs/symbol#%E5%B1%9E%E6%80%A7%E5%90%8D%E7%9A%84%E9%81%8D%E5%8E%86
    const keys = type === 'array' ? undefined : Reflect.ownKeys(obj)
    const ret = keys || obj
    ret.forEach((value, key) => {
      if (keys) {
        key = value
      }
      clone[key] = deepClone(obj[key], clonedObj)
    })
  }

  return clone
}

// example
const obj = {
  dep: {
    str: '123213',
    age: 12,
    bool: true,
    nullVal: null,
    undefinedVal: undefined,
    arr: [1, 2, 3],
    obj: { a: 1, b: 2 },
    date: new Date(),
    regex: /hello/g,
  },
  func(x) {
    console.log(12321, x)
  },
  num: 43,
  symbol: Symbol('test'),
  [Symbol('symbol1')]: 'foo',
  bint: BigInt(100)
}

const clone = deepClone(obj)

console.log(clone)
// {
//   dep: {
//     str: "123213",
//     age: 12,
//     bool: true,
//     nullVal: null,
//     undefinedVal: undefined,
//     arr: [
//       1,
//       2,
//       3,
//     ],
//     obj: {
//       a: 1,
//       b: 2,
//     },
//     date: Sat Apr 10 2023 18:10:36 GMT+0800 (中国标准时间) {},
//     regex: /hello/g,
//   },
//   func: function(x) {
//     console.log(12321, x)
//   },
//   num: 43,
//   symbol: Symbol(test),
//   Symbol('symbol1'): 'foo',
//   bint: 100n,
// }
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112

# 参考资料