Hey Folks👋 hope you doing well.
So you must be thinking, "Clone an Object"??? whats the big deal?
Well, i also think this way until i encounter an issue which took me 2 days just to debug that i have done something terrible with cloning an object.
So lets see how can we clone objects in javascript
// we have a user object
const user = {
name:"Deepak Negi",
email:"st.deepak15@gmail.com"
}
Now, if we want to copy this user object, so? simple!
const copiedUser = user;
Easy right?... well thats the worst way of copying a user,it is clear that you have some misconceptions of what the statement const copiedUser = user;
does.
In JavaScript objects are passed and assigned by reference (more accurately the value of a reference), so user
and copiedUser
are both references to the same object.
// [Object1]<--------- user
const copiedUser = user;
// [Object1]<--------- user
// ^
// |
// ----------- copiedUser
As you can see after the assignment, both references are pointing to the same object.
const user = {
name:"Deepak Negi",
email:"st.deepak15@gmail.com"
}
const copiedUser = user;
copiedUser.name = "XYZ"
console.log(copiedUser) // {name:"XYZ",email:"st.deepak15@gmail.com"}
console.log(user) // {name:"XYZ",email:"st.deepak15@gmail.com"}
modifing any of them will change both of them :(
So then how we can create copy if we need to modify one and not the other?
1. Spread Operator
const spreadUser = {...user}
spreadUser.name = "XYZ"
console.log(spreadUser) // {name:"XYZ",email:"st.deepak15@gmail.com"}
console.log(user) // {name:"Deepak Negi",email:"st.deepak15@gmail.com"}
2. Object.assign()
const assignUser = Object.assign({}, user);
assignUser.name = "XYZ"
console.log(assignUser) // {name:"XYZ",email:"st.deepak15@gmail.com"}
console.log(user) // {name:"Deepak Negi",email:"st.deepak15@gmail.com"}
Yaassss we finally got it!
If you think thats it.. so no... there much more to know, now we have added some more data in the user object and now lets see what happen.
const user = {
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"New Delhi",
state:"Delhi",
zipcode: 000000,
country:"India"
}
}
const spreadUser = {...user}
spreadUser.address.city = "Pune"
spreadUser.address.state = "Mumbai"
console.log(spreadUser)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"Pune",
state:"Mumbai",
zipcode: 000000,
country:"India"
}
}
console.log(user)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"Pune",
state:"Mumbai",
zipcode: 000000,
country:"India"
}
}
You see the problem, our actual user object is also changed now and this happens with Object.assign()
method as well.
But why?
Because of the shallow copying i.e. object spread operator, as well as Object.assign, does not clone the values of nested objects, but copies the reference to the nested object. That's called shallow copying.
Then what should we do? Deep copy?
Yes, Deep copy/Deep clone will copies object, even nested properties, to do so serialize the object to JSON and parse it back to a JS object.
const user = {
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"New Delhi",
state:"Delhi",
zipcode: 000000,
country:"India"
}
}
const deepCopiedUser = JSON.parse(JSON.stringify(user))
deepCopiedUser.address.city = "Pune"
deepCopiedUser.address.state = "Mumbai"
console.log(deepCopiedUser)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"Pune",
state:"Mumbai",
zipcode: 000000,
country:"India"
}
}
console.log(user)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"New Delhi",
state:"Delhi",
zipcode: 000000,
country:"India"
}
}
So now our original user
object doesn't change when we modify the deepCopiedUser
.
Beware using the
JSON.parse(JSON.stringify(user))
if you're dealing with date, functions, RegExps, Maps, Sets or other complex types within your object. The JSON method can't handle these types.
So for such cases the lodash clonedeep method is probably the best way to go.
import {cloneDeep} from 'lodash'
or
const {cloneDeep} = require('lodash')
const user = {
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"New Delhi",
state:"Delhi",
zipcode: 000000,
country:"India"
}
}
const deepCloneUser = cloneDeep(user)
deepCloneUser.address.city = "Pune"
deepCloneUser.address.state = "Mumbai"
console.log(deepCloneUser)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"Pune",
state:"Mumbai",
zipcode: 000000,
country:"India"
}
}
console.log(user)
// console output
{
name:"Deepak Negi",
email:"st.deepak15@gmail.com",
address:{
line1:"ABC, Tower X",
city:"New Delhi",
state:"Delhi",
zipcode: 000000,
country:"India"
}
}
Let me know in the comment what do you think the best way for deep cloning the object.
Top comments (0)