Skip to content

Commit a4e68e4

Browse files
committed
🎨 update: 深拷贝
1 parent b0560a3 commit a4e68e4

File tree

2 files changed

+245
-44
lines changed

2 files changed

+245
-44
lines changed

JavaScript/浅拷贝和深拷贝.md

Lines changed: 125 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
---
2+
{
3+
"title": "浅拷贝和深拷贝",
4+
}
5+
---
16
关于为什么会有深拷贝和浅拷贝,实际上就是基本类型和引用类型的问题,可以参考我这篇文章:[JS进阶】你真的掌握变量和类型了吗](http://www.conardli.top/2019/05/28/%E3%80%90JS%E8%BF%9B%E9%98%B6%E3%80%91%E4%BD%A0%E7%9C%9F%E7%9A%84%E6%8E%8C%E6%8F%A1%E5%8F%98%E9%87%8F%E5%92%8C%E7%B1%BB%E5%9E%8B%E4%BA%86%E5%90%97/)
27

38
### 浅拷贝
@@ -15,36 +20,134 @@ arr.concat();
1520

1621
`JSON.parse(JSON.stringify(obj))`
1722

23+
24+
1825
手动实现:
1926

20-
代码其实可以更简单,都使用`forin`就好了,但是`forin`效率非常差,这里区分数组和对象,数组使用`for`循环就好了
27+
> 代码解析后面放出来
2128
2229
```js
23-
function clone(target) {
24-
if (typeof target === 'object') {
25-
let cloneTarget;
26-
if (Array.isArray(target)) {
27-
cloneTarget = [];
28-
for (let i = 0; i < target.length; i++) {
29-
cloneTarget[i] = clone(target[i]);
30-
}
31-
} else {
32-
cloneTarget = {};
33-
for (const key in target) {
34-
cloneTarget[key] = clone(target[key]);
35-
}
36-
}
37-
return cloneTarget;
38-
} else {
30+
const mapTag = '[object Map]';
31+
const setTag = '[object Set]';
32+
const arrayTag = '[object Array]';
33+
const objectTag = '[object Object]';
34+
const argsTag = '[object Arguments]';
35+
36+
const boolTag = '[object Boolean]';
37+
const dateTag = '[object Date]';
38+
const numberTag = '[object Number]';
39+
const stringTag = '[object String]';
40+
const symbolTag = '[object Symbol]';
41+
const errorTag = '[object Error]';
42+
const regexpTag = '[object RegExp]';
43+
44+
const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];
45+
46+
47+
function forEach(array, iteratee) {
48+
let index = -1;
49+
const length = array.length;
50+
while (++index < length) {
51+
iteratee(array[index], index);
52+
}
53+
return array;
54+
}
55+
56+
function isObject(target) {
57+
const type = typeof target;
58+
return target !== null && (type === 'object' || type === 'function');
59+
}
60+
61+
function getType(target) {
62+
return Object.prototype.toString.call(target);
63+
}
64+
65+
function getInit(target) {
66+
const Ctor = target.constructor;
67+
return new Ctor();
68+
}
69+
70+
function cloneSymbol(targe) {
71+
return Object(Symbol.prototype.valueOf.call(targe));
72+
}
73+
74+
function cloneReg(targe) {
75+
const reFlags = /\w*$/;
76+
const result = new targe.constructor(targe.source, reFlags.exec(targe));
77+
result.lastIndex = targe.lastIndex;
78+
return result;
79+
}
80+
81+
function cloneOtherType(targe, type) {
82+
const Ctor = targe.constructor;
83+
switch (type) {
84+
case boolTag:
85+
case numberTag:
86+
case stringTag:
87+
case errorTag:
88+
case dateTag:
89+
return new Ctor(targe);
90+
case regexpTag:
91+
return cloneReg(targe);
92+
case symbolTag:
93+
return cloneSymbol(targe);
94+
default:
95+
return null;
96+
}
97+
}
98+
99+
function clone(target, map = new WeakMap()) {
100+
101+
// 克隆原始类型
102+
if (!isObject(target)) {
39103
return target;
40-
}
41104
}
42-
```
43105

44-
### 循环引用
106+
// 初始化
107+
const type = getType(target);
108+
let cloneTarget;
109+
if (deepTag.includes(type)) {
110+
cloneTarget = getInit(target, type);
111+
} else {
112+
return cloneOtherType(target, type);
113+
}
114+
115+
// 防止循环引用
116+
if (map.get(target)) {
117+
return target;
118+
}
119+
map.set(target, cloneTarget);
45120

121+
// 克隆set
122+
if (type === setTag) {
123+
target.forEach(value => {
124+
cloneTarget.add(clone(value));
125+
});
126+
return cloneTarget;
127+
}
128+
129+
// 克隆map
130+
if (type === mapTag) {
131+
target.forEach((value, key) => {
132+
cloneTarget.set(key, clone(value));
133+
});
134+
return cloneTarget;
135+
}
136+
137+
// 克隆对象和数组
138+
const keys = type === arrayTag ? undefined : Object.keys(target);
139+
forEach(keys || target, (value, key) => {
140+
if (keys) {
141+
key = value;
142+
}
143+
cloneTarget[key] = clone(target[key], map);
144+
});
46145

47-
### 其他类型
146+
return cloneTarget;
147+
}
48148

149+
module.exports = {
150+
clone
151+
};
49152

50-
### 函数拷贝
153+
```

docs/JavaScript/浅拷贝和深拷贝.md

Lines changed: 120 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,134 @@ arr.concat();
2020

2121
`JSON.parse(JSON.stringify(obj))`
2222

23+
24+
2325
手动实现:
2426

25-
代码其实可以更简单,都使用`forin`就好了,但是`forin`效率非常差,这里区分数组和对象,数组使用`for`循环就好了
27+
> 代码解析后面放出来
2628
2729
```js
28-
function clone(target) {
29-
if (typeof target === 'object') {
30-
let cloneTarget;
31-
if (Array.isArray(target)) {
32-
cloneTarget = [];
33-
for (let i = 0; i < target.length; i++) {
34-
cloneTarget[i] = clone(target[i]);
35-
}
36-
} else {
37-
cloneTarget = {};
38-
for (const key in target) {
39-
cloneTarget[key] = clone(target[key]);
40-
}
41-
}
42-
return cloneTarget;
43-
} else {
30+
const mapTag = '[object Map]';
31+
const setTag = '[object Set]';
32+
const arrayTag = '[object Array]';
33+
const objectTag = '[object Object]';
34+
const argsTag = '[object Arguments]';
35+
36+
const boolTag = '[object Boolean]';
37+
const dateTag = '[object Date]';
38+
const numberTag = '[object Number]';
39+
const stringTag = '[object String]';
40+
const symbolTag = '[object Symbol]';
41+
const errorTag = '[object Error]';
42+
const regexpTag = '[object RegExp]';
43+
44+
const deepTag = [mapTag, setTag, arrayTag, objectTag, argsTag];
45+
46+
47+
function forEach(array, iteratee) {
48+
let index = -1;
49+
const length = array.length;
50+
while (++index < length) {
51+
iteratee(array[index], index);
52+
}
53+
return array;
54+
}
55+
56+
function isObject(target) {
57+
const type = typeof target;
58+
return target !== null && (type === 'object' || type === 'function');
59+
}
60+
61+
function getType(target) {
62+
return Object.prototype.toString.call(target);
63+
}
64+
65+
function getInit(target) {
66+
const Ctor = target.constructor;
67+
return new Ctor();
68+
}
69+
70+
function cloneSymbol(targe) {
71+
return Object(Symbol.prototype.valueOf.call(targe));
72+
}
73+
74+
function cloneReg(targe) {
75+
const reFlags = /\w*$/;
76+
const result = new targe.constructor(targe.source, reFlags.exec(targe));
77+
result.lastIndex = targe.lastIndex;
78+
return result;
79+
}
80+
81+
function cloneOtherType(targe, type) {
82+
const Ctor = targe.constructor;
83+
switch (type) {
84+
case boolTag:
85+
case numberTag:
86+
case stringTag:
87+
case errorTag:
88+
case dateTag:
89+
return new Ctor(targe);
90+
case regexpTag:
91+
return cloneReg(targe);
92+
case symbolTag:
93+
return cloneSymbol(targe);
94+
default:
95+
return null;
96+
}
97+
}
98+
99+
function clone(target, map = new WeakMap()) {
100+
101+
// 克隆原始类型
102+
if (!isObject(target)) {
44103
return target;
45-
}
46104
}
47-
```
48105

49-
### 循环引用
106+
// 初始化
107+
const type = getType(target);
108+
let cloneTarget;
109+
if (deepTag.includes(type)) {
110+
cloneTarget = getInit(target, type);
111+
} else {
112+
return cloneOtherType(target, type);
113+
}
50114

115+
// 防止循环引用
116+
if (map.get(target)) {
117+
return target;
118+
}
119+
map.set(target, cloneTarget);
51120

52-
### 其他类型
121+
// 克隆set
122+
if (type === setTag) {
123+
target.forEach(value => {
124+
cloneTarget.add(clone(value));
125+
});
126+
return cloneTarget;
127+
}
128+
129+
// 克隆map
130+
if (type === mapTag) {
131+
target.forEach((value, key) => {
132+
cloneTarget.set(key, clone(value));
133+
});
134+
return cloneTarget;
135+
}
136+
137+
// 克隆对象和数组
138+
const keys = type === arrayTag ? undefined : Object.keys(target);
139+
forEach(keys || target, (value, key) => {
140+
if (keys) {
141+
key = value;
142+
}
143+
cloneTarget[key] = clone(target[key], map);
144+
});
145+
146+
return cloneTarget;
147+
}
53148

149+
module.exports = {
150+
clone
151+
};
54152

55-
### 函数拷贝
153+
```

0 commit comments

Comments
 (0)