DEV Community

Cover image for ES6: How to Clone an Object in javascript ?
deepak-negi-web
deepak-negi-web

Posted on

ES6: How to Clone an Object in javascript ?

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"
} 
Enter fullscreen mode Exit fullscreen mode

Now, if we want to copy this user object, so? simple!

const copiedUser = user;
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"}
Enter fullscreen mode Exit fullscreen mode

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"}

Enter fullscreen mode Exit fullscreen mode

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"}

Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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"
  }
}

Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

Finally!!

Let me know in the comment what do you think the best way for deep cloning the object.

Top comments (0)