DEV Community

Cover image for 3 ways to clone an object in Javascript
Nithish Kumar
Nithish Kumar

Posted on

3 ways to clone an object in Javascript

Before proceeding, let me explain very briefly about Primitive and Reference types in Javascript.

Primitive and Reference type

Javascript has 5 data types that can contain values. Number, string, Boolean , null and undefined. These are referred to as primitive data types. Basically these are passed by value.
Javascript has 3 data types that are passed by reference. Object,Functions and Arrays. Technically, these are all objects and called as reference data types
Primitive data types are immutable, which means their value cannot be modified once created.
Whereas, objects and arrays are mutable , meaning their value can be altered after creation.

Consider the following examples.

Let us start by copying/cloning a string

let message1 = 'hello everyone'
let message2 = message1
message2 = 'hello world'

console.log(message1) // 'hello everyone' ✅
console.log(message2) // 'hello world' ✅
Enter fullscreen mode Exit fullscreen mode

So for so good,, everything is working as expected .
Let us implement the same logic for object

let myObj1 = {
  name : 'John Doe',
  age: 34
}

let myObj2 = myObj1
myObj2.name = 'Michael'

console.log(myObj1) //{name: 'Michael', age: 34} 😲 -> why does the original object `myObj2` got affected ?
console.log(myObj2) //{name: 'Michael', age: 34} ✅

Enter fullscreen mode Exit fullscreen mode

🤔🤔
That's because objects are reference type(passed by reference). So, when you use '=', the pointer to the memory address of myObj1 is copied to myObj2. Not the actual value is copied. Since, reference type don't hold values, they are pointer to the value in memory space.

So,, how do you clone an object?

We can use variety of techniques such as the spread operator(...) or Object.assign() or with JSON.parse() and JSON.stringify().

1. Using spread (...)

let myObj1 = {
  name: 'John Doe',
  age: 34
}
let myObj2 = {...myObj1} 
myObj2.name = 'Michael'

console.log(myObj1) // {name: "John Doe", age: 34} ✅ Original object `myObj1` is not changed
console.log(myObj2) // {name: "Michael", age: 34} ✅
Enter fullscreen mode Exit fullscreen mode

2. Using Object.assign()

let item1 = {
  pen: 23,
  pencil: 45
}

let item2 = Object.assign({}, item1)
item2.pen = 100
console.log(item1) // {pen: 23, pencil: 45} ✅ Original object `item1` is not changed
console.log(item2) // {pen: 100, pencil: 45} ✅
Enter fullscreen mode Exit fullscreen mode

Note

Both of the above techniques only does a shallow copy(only the outer part). If you want to perform a deep copy(nested part), there are a few approaches to this problem. The simple technique is by using our well known friend JSON.parse() and JSON.stringify(). But, it is not recommended to do deep copy using this technique, instead , you can use libraries such
as lodash, which is easy to implement and also robust.

3. Using JSON (Not Recommended)

let obj1 = {a:1,b:2,c:{d :3}}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj2.c.d = 45;

console.log(obj1) // {a: 1,b: 2,c: {d: 3}} ✅
console.log(obj2) // {a: 1,b: 2,c: {d: 45}} ✅
Enter fullscreen mode Exit fullscreen mode

Note

If you try to do the above example with spread or Object.assign(),it only modifies
the outer part(shallow).

For example,

let obj = {a:1,b:2,c:{d :3}}
let shallowObj = {...obj}
shallowObj.b = 20
shallowObj.c.d = 30

console.log(shallowObj) //{a: 1,b: 20,c: {d: 30}} 😎
console.log(obj) //{a: 1,b: 2,c: {d: 30}}  🤯 -> Notice that only `b` value is not modified from the original `obj`, whereas, `d` value is modified
Enter fullscreen mode Exit fullscreen mode

A shallow copy means the first level is copied, deeper levels are referenced.
This is where, shallow and deep copy plays an important role.

Thanks for reading my post 🙌🙌

👉 Additional Resources

MDN Web Docs:Object.assign()
MDN Web Docs:JSON.parse()
MDN Web Docs:JSON.stringify()
Shallow vs Deep Copy
Primitive vs Reference Type
Why should you use lodash for deep copy

Top comments (6)

Collapse
 
lexlohr profile image
Alex Lohr

Here's my proposal for a native Object.clone() method, including a workable polyfill: github.com/atk/object-clone-propos...

Collapse
 
dimer191996 profile image
Dimer Bwimba

hanks for sharing.

Collapse
 
nithish_13 profile image
Nithish Kumar

Thanks for sharing. I will keep that in my code notes. :)

Collapse
 
davidhavlin profile image
davidhavlin

Good article but why is json not recommended? When i need deep copy its the only way right?

Collapse
 
nithish_13 profile image
Nithish Kumar • Edited

There are lot of reasons . The main disadvantage is , JSON.stringify() converts Date objects to string. If the value of the key is undefined, when doing with JSON.stringify(), the key is lost. For example,

let obj1 = {
  date : new Date(),
  name : undefined
}
console.log(JSON.parse(JSON.stringify(obj1))  // would return {date: "2021-05..." }
Enter fullscreen mode Exit fullscreen mode

Notice that the name attribute(or key) is lost.
Also,, it causes performance issue. So developers prefer either JQuery or lodash to implement deep copy.

Collapse
 
aalphaindia profile image
Pawan Pawar

Keep sharing!