Deep Cloning Objects In JavaScript
In this article, we are going to discuss deep cloning objects in JavaScript. In JavaScript, Object play a major role in storing and sharing data.
Because objects in JavaScript are references values, we can’t simply just copy using the =
. So your first question might be, why can’t I use =
. Let’s see what happens if we do that:
const obj = { "Red Apple": "🍎", "Green Apple": "🍏" }; const obj2 = obj; console.log(obj); //{ "Red Apple": "🍎", "Green Apple": "🍏" } console.log(obj2);//{ "Red Apple": "🍎", "Green Apple": "🍏" }
So now, we can see what happens when we manipulate the copied object(obj2) in the below code snippet
obj2["Grapes"] = "🍇"; console.log(obj); //{ "Red Apple": "🍎", "Green Apple": "🍏", "Grapes": "🍇"} console.log(obj2); //{ "Red Apple": "🍎", "Green Apple": "🍏", "Grapes": "🍇"}
I have changed obj2
but why was obj
also mutated. That’s because Objects are reference types. So when we use =
, it copied the pointer to the memory space it occupies.
Reference types don’t hold values, they are a pointer to the value in memory. But no worries, here are 3 ways for you to clone an object😉
1. Using Spread
Using spread will clone your object. Note this will be a shallow copy.
const animal = { Dog: '🐶', Monkey: '🐒' }; const cloneAnimal = { ...animal }; console.log(cloneAnimal); // { Dog: '🐶', Monkey: '🐒' }
2. Using Object.assign
And it’s also a shallow copy. Note the empty {}
as the first argument, this will ensure you don’t mutate the original object 👍
const animal = { Dog: '🐶', Monkey: '🐒' }; const cloneAnimal = Object.assign({}, animal); console.log(cloneAnimal); // { Dog: '🐶', Monkey: '🐒' }
3. Using JSON
And this will be the final way gives us the deep copy. For a more robust solution, I would recommend using something like lodash
const animal = { Dog: '🐶', Monkey: '🐒' }; const cloneAnimal = JSON.parse(JSON.stringify(animal)); console.log(cloneAnimal); // { Dog: '🐶', Monkey: '🐒' }
Shallow Clone vs Deep Clone
When we do the Shallow copy using the spread(…) and Object.assign
it doesn’t work for nested object. A shallow copy means the first level is copied, deeper levels are referenced.
const nestedObject = {animal: '🐶', property: {color: 'black'}}; const shallowCloneObj = { ...nestedObject }; shallowCloneObj.property.color = 'white'; console.log(shallowCloneObj); // {animal: '🐶', property: {color: 'white'}}; console.log(nestedObject); // {animal: '🐶', property: {color: 'white'}}; <-- ☹️
Let’s take the same example but applying a deep copy using “JSON”
const nestedObject = {animal: '🐶', property: {color: 'black'}}; const shallowCloneObj = JSON.parse(JSON.stringify(nestedObject)); shallowCloneObj.property.color = 'white'; console.log(shallowCloneObj); // {animal: '🐶', property: {color: 'white'}}; console.log(nestedObject); // {animal: '🐶', property: {color: 'black'}}; <-- 👍
As we see, the deep copy is a true copy for nested objects. Often time shallow copy is good enough, you don’t really need a deep copy.
It’s all up to you, is it fine to mutate your original object then you can go with shallow copy. Otherwise, you can use deep copy.
For More Reference
- MDN Web Docs: Object.assign
- Stack Overflow: What is the most efficient way to deep clone an object in JavaScript?
- Stack Overflow: Object spread vs. Object.assign
- Deep Clone using External Libraries
Happy Coding 🙂