实现一个深拷贝

# 实现一个深拷贝

function myDeepCopy (obj, map = new WeakMap()) {

 if (typeof obj !== 'object') return;

 if (obj instanceof Date) {
  const copyDate = new Date();
  copyDate.setTime(obj.getTime());
  return copyDate;
 }

 if (obj instanceof RegExp) {
  const Constructor = obj.constructor;
  return new Constructor(obj);
 }

 let newObj = obj instanceof Array ? [] : {};
 if (map.get(obj)) {
  return map.get(obj);
 }

 map.set(obj, newObj);
 for(let key in obj) {
  if (obj.hasOwnProperty(key)) {
   newObj[key] = 
    obj[key] instanceof Object ? myDeepCopy(obj[key], map) : obj[key];
  }
 }

 return newObj;
}
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
const mapTag = '[object Map]'
const setTag = '[object Set]'
const arrayTag = '[object Array]'
const objectTag = '[object Object]'
const argsTag = '[object Arguments]'
const boolTag = '[object Boolean]'
const dateTag = '[object Date]'
const numberTag = '[object Number]'
const stringTag = '[object String]'
const symbolTag = '[object Symbol]'
const errorTag = '[object Error]'
const regexTag = '[object RegExp]'
const funcTag = '[object Function]'

const deepTags = [
 mapTag,
 setTag,
 arrayTag,
 objectTag,
 boolTag,
 boolTag,
 dateTag,
 numberTag,
 stringTag,
 symbolTag,
 errorTag,
 regexTag,
 funcTag,
]

function forEach(array, iteratee) {
 let index = -1;
 const { length } = array
 while (++index < length) {
  iteratee(array[index], index)
 }

 return array
}

function isObject(target) {
 const type = typeof target
 return target && (type === 'object' || type === 'function')
}

function getType(target) {
 return Object.prototype.toString.call(target)
}

function getInit(target) {
 const Ctor = target.constructor
 return new Ctor()
}

function cloneSymbol(target) {
 return Object(Symbol.prototype.valueOf.call(target))
}

function cloneReg(target) {
 const reFlags = /\w*$/
 const result = new target.constructor(target.source, reFlags.exec(target);
 
 result.lastIndex = target.lastIndex
 return result
 )

 function cloneFunction(func) {
  const bodyReg = /(?<={)(.|\n)+(?=})/m
  const paramReg = /(?<=\().+(?=\)\s+{)/
  const funcString = func.toString()

  if (func.prototype) {
   const param = paramReg.exec(funcString)
   const body = bodyReg.exec(funcString)
   if (body) {
    if (param) {
     const paramArr = param[0].split(',')
     return new Function(...paramArr, body[0])
    }
    return new Function(body[0])
   }
   return null
  }
  return eval(funcString)
 }

 function cloneOtherType(target, type) {
  const Ctor = target.constructor
  switch (type) {
   case boolTag:
   case numberTag:
   case stringTag:
   case errorTag:
   case dateTag:
    return new Ctor(target)
   case regexTag:
    return new cloneReg(target)
   case symbolTag:
    return cloneFunction(target)
   case funcTag:
    return cloneFunction(target)
  
   default:
    return null
  }
 }

 function clone(target, map = new WeakMath()) {
  // 克隆原始类型
  if (!isObject(target)) return target

  // 初始化
  const type = getType(target)
  let cloneTarget

  if(deepTag.includes(type)) cloneTarget = getInit(target, type)
  else return cloneOtherType(target, type)

  // 防止循环引用
  if (map.get(target)) return target

  map.set(target, cloneTarget)

  // 克隆set
  if (type === setTag) {
   target.forEach((value) => cloneTarget.add(key, clone(value)))

   return cloneTarget
  }

  // 克隆对象和数组
  const keys = type === arrayTag ? undefined : Object.keys(target)
  forEach(keys || target, (value, key) => {
   if (keys) key = value
   cloneTarget[key] = clone(target[key], map)
  })

  return cloneTarget
 }
}
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
function deepCopy (obj, cache = []) {
 if (obj === null || typeof obj !== 'object') {
  return obj
 }
 if (Object.prototype.toString.call(obj) === '[object Date]') return new Date(obj)
 if (Object.prototype.toString.call(obj) === '[object RegExp]') return new RegExp(obj)
 if (Object.prototype.toString.call(obj) === '[object Error]') return new Error(obj)

 const item = cache.filter(item = > item.original === obj)[0]

 if (item) return item.copy

 let copy = Array.isArray(obj) ? [] : {}
 cache.push({
  original: obj,
  copy
 })

 Object.keys(obj).forEach(key => {
  copy[key] = deepCopy(obj[key], cache)
 })
 return copy
}
deepCopy($obj)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
上次更新: 2022/7/12 上午3:07:14