introduction
This article is going to talk about 5 ways to depp copy objects in JavaScript. Before we get started, we will look into what's the different between Shallow copy and Deep copy.
Shallow copy
vs Deep copy
Shallow copy
stores references of objects to the original memory address.
On the other hands, Deep copy
stores copies of the object's value
Shallow copy examples
const a = {
name: 'a',
}
const copies = a
cloned.name = 'new name'
console.log(a) // {name: "new name"}
console.log(cloned) // {name: "new name"}
cloned variable which is copied with =
operator changed property name
in a
variable.
Shallow copy
reflects changes made to the new and copied object in the original object, but Deep copy
doesn't reflect changes.
Deep copy
From now on, we are going to talk about Deep copy.
Deep copy - JSON.stringify()
and JSON.parse()
JSON.stringify()
method converts JavaScript value like primitive values, Object and Array to JSON string.
JSON.parse()
method parses a JSON string to JavaScript. It's contrary to JSON.stringify()
.
Combining both of these method allows to create a copy of an object.
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = JSON.parse(JSON.stringify(user))
cloned.name = 'John'
cloned.address.country = 'Japan'
console.log(user) // {name: "Arthur", age: 20, address: {country: "Canada"}
console.log(cloned) // {name: "John", age: 20, address: {country: "Japan"}
You can see cloned doesn't change original value. It doesn't change nested object too. However, this way can't copy function value
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = JSON.parse(JSON.stringify(user))
cloned.setAge(5)
You'll get TypeError: cloned.setAge is not a function
error message.
Pros
- Deep copies nested objects
- Well known coding style
Cons
- It doesn't copy functions
- Low performance
Depp copy - Object.assign()
Object.assign()
method copies all values from one or more source objects to a target object. It returns the modified target object.
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = Object.assign({}, user)
cloned.name = 'John'
cloned.address.country = 'Japan'
cloned.setAge(5)
console.log(user) // {name: "Arthur", age: 20, address: {country: "Japan"}
console.log(cloned) // {name: "John", age: 5, address: {country: "Japan"}
Advantage of Object.assign()
method is that Object.assign()
method copies not only objects but also functions, so you can use function in object.
Pros
- Deep copies objects and functions
Cons
- It doesn't copy nested objects
Deep copy - The ...
spread Syntax.
The ...
spread syntax allows iterable to be expanded
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = {...user}
cloned.name = 'John'
cloned.address.country = 'Japan'
cloned.setAge(5)
console.log(user) // {name: "Arthur", age: 20, address: {country: "Japan"}
console.log(cloned) // {name: "John", age: 5, address: {country: "Japan"}
Unfortunately, The spread syntax doesn't copy nested object like Object.assign()
method. However, there is a way to copy nested object
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = {...user,
address: {
...user.address
}
}
cloned.address.country = 'Japan'
console.log(user) // {name: "John", age: 20, address: {country: "Canada"}
console.log(cloned) // {name: "John", age: 20, address: {country: "Japan"}
If you use the spread syntax in nested object, they will be deep copied.
Pros
- Deep copies objects and functions
- Easy to use
Cons
- Nested object can be deep copy, but it's very annoying to use.
Deep copy - lodash library
The lodash
is a modern JavaScript utility library delivering modularity, performance & extras.
The lodash
provides utility called cloneDeep()
method.
import _ from 'lodash'
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = _.cloneDeep(user)
cloned.name = 'John'
cloned.address.country = 'Japan'
cloned.setAge(5)
console.log(user) // {name: "Arthur", age: 20, address: {country: "Canada"}
console.log(cloned) // {name: "John", age: 5, address: {country: "Japan"}
cloneDeep()
method in lodash
library allows deep copy, nested object and functions.
Pros
- Deep copies objects, nested objects and functions
Cons
- You should install the library, and it will increase your project size.
Deep copy structuredClone()
The structuredClone()
global method creates a deep clone of a given value using the structured clone algorithm.
const user = {
name: 'Arthur',
age: 20,
address: {
country: 'Canada'
},
setAge: function (newAge) {
this.age = newAge
}
}
const cloned = structuredClone(user)
cloned.name = 'John'
cloned.address.country = 'Japan'
// cloned.setAge(5) // ERROR!
console.log(user) // {name: "Arthur", age: 20, address: {country: "Japan"}
console.log(cloned) // {name: "John", age: 5, address: {country: "Japan"}
Pros
- Deep copies nested objects
- Better performance than
JSON.stringify()
andJSON.parse()
.
Cons
- It doesn't copy functions
- It cannot clone DOM elements
- Low version of browser and Node.js may not supported