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' ✅
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} ✅
🤔🤔
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} ✅
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} ✅
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()
andJSON.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}} ✅
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
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)
Here's my proposal for a native
Object.clone()
method, including a workable polyfill: github.com/atk/object-clone-propos...hanks for sharing.
Thanks for sharing. I will keep that in my code notes. :)
Good article but why is json not recommended? When i need deep copy its the only way right?
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 withJSON.stringify()
, the key is lost. For example,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.
Keep sharing!