-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCloning An Object.js
More file actions
141 lines (106 loc) · 4.32 KB
/
Cloning An Object.js
File metadata and controls
141 lines (106 loc) · 4.32 KB
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
/* Copying objects in JavaScript can be tricky. Some ways perform a shallow copy, which is the default behavior
in most of the cases.
Deep copy vs Shallow copy
A shallow copy successfully copies primitive types like numbers and strings, but any object reference will not be
recursively copied, but instead the new, copied object will reference the same object. If an object references
other objects, when performing a shallow copy of the object, you copy the references to the external objects.
When performing a deep copy, those external objects are copied as well, so the new, cloned object is completely
independent from the old one. Looking out how to deep clone an object in JavaScript on the internet, you’ll find
lots of answers but not always the answer is correct.
Lodash is the easiest option to perform a deep copy. Lodash is a library that’s well tested, very popular and
carefully maintained. Lodash offers the very convenient clone and deepclone functions to perform shallow and deep
cloning. Lodash has the feature of importing single functions separately in your project to reduce a lot the
size of the dependency.
*/
//in node.js
const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')
/* An example that shows those two functions in use. First create a shallow copy, and edit the i.color property,
which propagates to the copied object. In the deep clone, this does not happen.
*/
const clone = require('lodash.clone')
const clonedeep = require('lodash.clonedeep')
const externalObject = {
color: 'red'
}
const original = {
a: new Date(),
b: NaN,
c: new Function(),
d: undefined,
e: function() {},
f: Number,
g: false,
h: Infinity,
i: externalObject
}
const cloned = clone(original)
externalObject.color = 'blue'
console.info('⬇️ shallow cloning 🌈')
console.info(
'✏️ Notice the i.color property we changed on original is also changed in the shallow copy'
)
console.log(original)
console.log(cloned)
const deepcloned = clonedeep(original)
externalObject.color = 'yellow'
console.log('')
console.info('⬇️ deep cloning 🌈')
console.info('✏️ Notice the i.color property does not propagate any more')
console.log(original)
console.log(deepcloned)
//Object.assign() performs a shallow copy of an object, not a deep clone.
const copied = Object.assign({}, original)
/* Being a shallow copy, values are cloned, and objects references are copied (not the objects themselves), so
if you edit an object property in the original object, that’s modified also in the copied object, since the
referenced inner object is the same:
*/
const original = {
name: 'Fiesta',
car: {
color: 'blue'
}
}
const copied = Object.assign({}, original)
original.name = 'Focus'
original.car.color = 'yellow'
copied.name //Fiesta
copied.car.color //yellow
//The Object Spread operator provides a very convenient way to perform a shallow clone, equivalent to what Object.assign() does.
let copied = { ...original }
/* Wrong solutions - Online you will find many suggestions. Here are some wrong ones:
Using Object.create()
Note: not recommended
const copied = Object.create(original)
This is wrong, it’s not performing any copy. Instead, the original object is being used as the prototype of copied.
Apparently it works, but under the hoods it does not:
const original = {
name: 'Fiesta'
}
const copied = Object.create(original)
copied.name //Fiesta
original.hasOwnProperty('name') //true
copied.hasOwnProperty('name') //false
JSON serialization
Note: not recommended
Some recommend transforming to JSON:
const cloned = JSON.parse(JSON.stringify(original))
This has unexpected consequences. By doing this you will lose any Javascript property that has no equivalent type
in JSON, like Function or Infinity. Any property that’s assigned to undefined will be ignored by JSON.stringify,
causing them to be missed on the cloned object.
Also, some objects are converted to strings, like Date objects for example, (also, not taking into account the
timezone and defaulting to UTC), Set, Map and many others:
JSON.parse(
JSON.stringify({
a: new Date(),
b: NaN,
c: new Function(),
d: undefined,
e: function() {},
f: Number,
g: false,
h: Infinity
})
)
This only works if you do not have any inner objects and functions, but just values.
*/