-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path手写实用的深拷贝方法.js
123 lines (105 loc) · 2.98 KB
/
手写实用的深拷贝方法.js
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
/**
* 手写深拷贝方法cloneDeep
* 深拷贝本质是解决共用内存地址所导致的数据错乱问题
let obj = {
a:undefined,
b:function(){
console.log('I am function');
},
c:NaN,
d:Symbol('d'),
e:new Date('2021-4-22'),
g:Infinity,
h:new RegExp('aa','g')
}
obj[Symbol('f')] = 'Symbol value';
let anotherObj = JSON.parse(JSON.stringify(obj));
console.log(obj);
console.log(anotherObj);
*【用JSON来拷贝的缺点】:
* 1、无法拷贝function 、Date、RegExp、undefined,Symbol,NaN,Infinity(Symbol会被直接忽略)
* 1.1 undefined,function,Symbol直接被忽略
* 1.2 Date转换成日期字符串
* 1.3 NaN转换成null
* 1.4 RegExp转换成{}
* 1.5 Infinity转换成null
* 2、Object里面不可枚举的属性会被忽略,无法拷贝
* 3、对象有循环引用,会报错
* 4、会抛弃对象的constructor,所有的构造函数会指向Object
* 思路:
* 1、判断数值的数据类型
* 2、根据特定数据类型进行具体的拷贝
* 2.1可遍历类型:遍历每个值递归处理
* 2.2不可遍历类型:根据类型进行赋值
* 2.3根据类型,通过constructor构造初始值然后拷贝内容
* 3、对于引用类型拷贝时,判断是否有循环引用
*
*/
// Populate the class2type map(Symbol:ES6 ,BigInt:ES10)
const class2type = {}
'Boolean Number String Function Array Date RegExp Object Error Symbol BigInt'
.split(' ')
.forEach((name) => {
class2type['[object ' + name + ']'] = name.toLowerCase() // 全部小写
})
// Get the type of object
function getType(obj) {
// Match null and undefined
if (obj == null) {
return obj + ''
}
// Reference type
if (typeof obj === 'object' || typeof obj === 'function') {
// Support: Android <=2.3 only (functionish RegExp)
return class2type[Object.prototype.toString.call(obj)] || 'object'
}
// Primitive type
return typeof obj
}
function isObject(obj) {
return obj !== null && (typeof obj === 'object' || typeof obj === 'function')
}
function cloneDeep(target, map = new WeakMap()) {
const type = getType(target)
// Boolean, Number, String, Symbol, BigInt
if (!isObject(target)) {
return target
}
// Date, RegExp
if (['date', 'regexp'].includes(type)) {
return new target.constructor(target)
}
// Function
if ('function' === type) {
return target
}
// Map
if ('map' === type) {
let map = new Map()
for (const key in target) {
map.set(key, map.get(key))
}
return map
}
// Resolve circular references
if (map.get(target)) {
return target
}
map.set(target, target)
// Array
if ('array' === type) {
let arr = []
for (let i = 0; i < target.length; i++) {
arr.push(cloneDeep(target[i]))
}
return arr
}
// Object
if ('object' === type) {
let obj = {}
for (let i in target) {
obj[i] = cloneDeep(target[i])
}
return obj
}
}