-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
69 lines (52 loc) · 1.7 KB
/
index.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
module.exports = clone;
/**
* Deep clone an object.
* Pass true as a second argument to construct prototypes, false to instantiate as plain objects.
* Pass true as a thrid argument to suppress calling of a custom clone() function on first recursive call.
* Unsafe for use on cyclical data structures. Does not copy functions as object properties.
*
* @param { Object } obj - an object to clone
* @param { boolean } [ cast = false ] - true to cast objects as prototypes
* @param { boolean } [ suppress = false ] - true to supress prototype.clone() on first recursive call
*/
function clone(obj, cast, suppress) {
// falsey primitive, null, or undefined
if (!obj) {
return obj;
}
// object
if (typeof obj == 'object') {
// array
if (Array.isArray(obj)) {
let retObj = new Array(obj.length);
for (let i = 0; i < obj.length; ++i) {
retObj[i] = clone(obj[i], cast);
}
return retObj;
// object
} else {
// date, regex, typed array / array buffer
if (obj instanceof Date || obj instanceof RegExp || obj instanceof ArrayBuffer) {
return new obj.constructor(obj);
// prototyped or plain object
} else {
// use clone function if available
if (cast && !suppress && typeof obj.clone == 'function') {
return obj.clone();
// create clone from prototype or plain object
} else {
let retObj = (cast && obj.constructor && obj.constructor.prototype != Object.prototype) ? new obj.constructor() : {};
for (let key in obj) {
// ignore functions: too much fuss with scope
if (typeof obj[key] != 'function') {
retObj[key] = clone(obj[key], cast);
}
}
return retObj;
}
}
}
}
// primitive or a function
return obj;
}