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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
import Stack from './Stack.js';
import arrayEach from './arrayEach.js';
import assignValue from './assignValue.js';
import cloneBuffer from './cloneBuffer.js';
import copyArray from './copyArray.js';
import copyObject from './copyObject.js';
import cloneArrayBuffer from './cloneArrayBuffer.js';
import cloneDataView from './cloneDataView.js';
import cloneRegExp from './cloneRegExp.js';
import cloneSymbol from './cloneSymbol.js';
import cloneTypedArray from './cloneTypedArray.js';
import copySymbols from './copySymbols.js';
import copySymbolsIn from './copySymbolsIn.js';
import getAllKeys from './getAllKeys.js';
import getAllKeysIn from './getAllKeysIn.js';
import getTag from './getTag.js';
import initCloneObject from './initCloneObject.js';
import isBuffer from './isBuffer.js';
import isObject from './isObject.js';
import isTypedArray from './isTypedArray.js';
import keys from './keys.js';
import keysIn from './keysIn.js';
/** Used to compose bitmasks for cloning. */
/** 用于为克隆合成位掩码。 */
const CLONE_DEEP_FLAG = 1;
const CLONE_FLAT_FLAG = 2;
const CLONE_SYMBOLS_FLAG = 4;
/** `Object#toString` result references. */
const argsTag = '[object Arguments]';
const arrayTag = '[object Array]';
const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const mapTag = '[object Map]';
const numberTag = '[object Number]';
const objectTag = '[object Object]';
const regexpTag = '[object RegExp]';
const setTag = '[object Set]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
const weakMapTag = '[object WeakMap]';
const arrayBufferTag = '[object ArrayBuffer]';
const dataViewTag = '[object DataView]';
const float32Tag = '[object Float32Array]';
const float64Tag = '[object Float64Array]';
const int8Tag = '[object Int8Array]';
const int16Tag = '[object Int16Array]';
const int32Tag = '[object Int32Array]';
const uint8Tag = '[object Uint8Array]';
const uint8ClampedTag = '[object Uint8ClampedArray]';
const uint16Tag = '[object Uint16Array]';
const uint32Tag = '[object Uint32Array]';
/** Used to identify `toStringTag` values supported by `clone`. */
/** 用于标识“clone”支持的“toStringTag”值。 */
const cloneableTags = {};
cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[
dataViewTag
] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[
float64Tag
] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[
mapTag
] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[
setTag
] = cloneableTags[stringTag] = cloneableTags[symbolTag] = cloneableTags[uint8Tag] = cloneableTags[
uint8ClampedTag
] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
cloneableTags[errorTag] = cloneableTags[weakMapTag] = false;
/** Used to check objects for own properties. */
/** 用于检查对象的自身属性。 */
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Initializes an object clone based on its `toStringTag`.
* 根据对象的“toStringTag”初始化对象克隆。
* **Note:** This function only supports cloning values with tags of
* `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`.
* *注意:**此函数仅支持使用的标签克隆值
* “布尔”,“日期”,“错误”,“地图”,“数量”,“正则表达式”,“设置”,或“字符串”。
* @private
* @param {Object} object 要克隆的对象。
* @param {string} tag 要克隆的对象的“toStringTag”。
* @param {boolean} [isDeep] 指定深度克隆。
* @returns {Object} 返回初始化的克隆。
*/
function initCloneByTag(object, tag, isDeep) {
const Ctor = object.constructor;
switch (tag) {
case arrayBufferTag:
return cloneArrayBuffer(object);
case boolTag:
case dateTag:
return new Ctor(+object);
case dataViewTag:
return cloneDataView(object, isDeep);
case float32Tag:
case float64Tag:
case int8Tag:
case int16Tag:
case int32Tag:
case uint8Tag:
case uint8ClampedTag:
case uint16Tag:
case uint32Tag:
return cloneTypedArray(object, isDeep);
case mapTag:
return new Ctor();
case numberTag:
case stringTag:
return new Ctor(object);
case regexpTag:
return cloneRegExp(object);
case setTag:
return new Ctor();
case symbolTag:
return cloneSymbol(object);
}
}
/**
* Initializes an array clone.
* 初始化数组克隆。
* @private
* @param {Array} array 要克隆的数组。
* @returns {Array} 返回初始化的克隆。
*/
function initCloneArray(array) {
const { length } = array;
const result = new array.constructor(length);
// Add properties assigned by `RegExp#exec`.
if (length && typeof array[0] === 'string' && hasOwnProperty.call(array, 'index')) {
result.index = array.index;
result.input = array.input;
}
return result;
}
/**
* The base implementation of `clone` and `cloneDeep` which tracks
* traversed objects.
* ' clone '和' cloneDeep '跟踪的基本实现
* 遍历对象。
* @private
* @param {*} value 要克隆的值。
* @param {number} bitmask 位掩码的旗帜。
* 1 - Deep clone 深克隆
* 2 - Flatten inherited properties 继承属性
* 4 - Clone symbols 克隆符号
* @param {Function} [customizer] 函数自定义克隆。
* @param {string} [key] The key of `value`.
* @param {Object} [object] The parent object of `value`.
* @param {Object} [stack] 跟踪遍历的对象及其克隆副本。
* @returns {*} 返回克隆的值。
*/
function baseClone(value, bitmask, customizer, key, object, stack) {
let result;
const isDeep = bitmask & CLONE_DEEP_FLAG;
const isFlat = bitmask & CLONE_FLAT_FLAG;
const isFull = bitmask & CLONE_SYMBOLS_FLAG;
if (customizer) {
result = object ? customizer(value, key, object, stack) : customizer(value);
}
if (result !== undefined) {
return result;
}
if (!isObject(value)) {
return value;
}
const isArr = Array.isArray(value);
const tag = getTag(value);
if (isArr) {
result = initCloneArray(value);
if (!isDeep) {
return copyArray(value, result);
}
} else {
const isFunc = typeof value === 'function';
if (isBuffer(value)) {
return cloneBuffer(value, isDeep);
}
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
result = isFlat || isFunc ? {} : initCloneObject(value);
if (!isDeep) {
return isFlat
? copySymbolsIn(value, copyObject(value, keysIn(value), result))
: copySymbols(value, Object.assign(result, value));
}
} else {
if (isFunc || !cloneableTags[tag]) {
return object ? value : {};
}
result = initCloneByTag(value, tag, isDeep);
}
}
// Check for circular references and return its corresponding clone.
// 检查循环引用并返回其对应的克隆。
stack || (stack = new Stack());
const stacked = stack.get(value);
if (stacked) {
return stacked;
}
stack.set(value, result);
if (tag == mapTag) {
value.forEach((subValue, key) => {
result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
return result;
}
if (tag == setTag) {
value.forEach((subValue) => {
result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack));
});
return result;
}
if (isTypedArray(value)) {
return result;
}
const keysFunc = isFull ? (isFlat ? getAllKeysIn : getAllKeys) : isFlat ? keysIn : keys;
const props = isArr ? undefined : keysFunc(value);
arrayEach(props || value, (subValue, key) => {
if (props) {
key = subValue;
subValue = value[key];
}
// Recursively populate clone (susceptible to call stack limits).
// 递归地填充克隆(容易受到调用堆栈限制)。
assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
});
return result;
}
export default baseClone;