Clone Javascript Objects
Objects in Javascript are references values, so you can't just copy using assing operator =
const car1 = { doors: 4, color: "blue" };
const car2 = car1;
car2.doors = 2;
console.log(car2); //{ doors: 2, color: 'blue' };
console.log(car1); //{ doors: 2, color: 'blue' }; 👀
I changed car2
but car1
also affected. It's because, when you use =
, really you are copied the pointer to the memory space it occupies. Reference types don't hold values, they are a pointer to the value in memory. To achive real clone, here are 2 ways:
Shallow clone
It makes a superficial clone of an object
Using Object.assing
The oldest way to do it. How we want clone an object, we start with empty object {}
for source
const car1 = { doors: 4, color: "blue" };
const car2 = Object.assing({}, car1);
car2.doors = 2;
console.log(car2); //{ doors: 2, color: 'blue' };
console.log(car1); //{ doors: 4, color: 'blue' }; ✅
Using Spread Operator
Since ECMAScript 6, we have available spread operator ...
const car1 = { doors: 4, color: "blue" };
const car2 = { ...car1 };
car2.doors = 2;
console.log(car2); //{ doors: 2, color: 'blue' };
console.log(car1); //{ doors: 4, color: 'blue' }; ✅
But remember, this way do a shallow clone. It means that, if you have nested objects, they won't be cloned and we'll have a reference again
const car1 = { doors: 4, color: "blue" };
car1.specs = { speed: 100, longitude: 300 };
const car2 = { ...car1 };
car2.specs.speed = 150;
console.log(car2); //{ doors: 4, color: 'blue', specs: { speed: 150, longitude: 100} };
console.log(car1); //{ doors: 4, color: 'blue', specs: { speed: 150, longitude: 100} }; 👀
Deep clone:
If we've interested on cloning nested objects too, we need a deep clone
Using JSON
This is a quick dirty way to get a deep clone. It has native support, so you don't need external deps. In practice, it is used more than it seems
const car1 = { doors: 4, color: "blue", specs: { speed: 100, longitude: 300 } };
const car2 = JSON.parse(JSON.stringify(car1));
car2.specs.speed = 150;
console.log(car2); //{ doors: 4, color: 'blue', specs: { speed: 150, longitude: 100} };
console.log(car1); //{ doors: 4, color: 'blue', specs: { speed: 100, longitude: 100} }; ✅
But not everything is so good. JSON method doesn't work with functions and order of properties in the cloned object may be different
const car1 = { doors: 4, color: "blue", specs: { speed: 100, longitude: 300 } };
car1.paint = function (newColor) {
this.color = newColor;
};
const car2 = JSON.parse(JSON.stringify(car1));
console.log(car2); //{ doors: 4, color: 'blue', specs: { speed: 100, longitude: 100}, paint: f };
console.log(car1); //{ doors: 4, color: 'blue', specs: { speed: 100, longitude: 100} }; 👀
Using external library
There are a lot of libraries (or you can create yourself 😎) that have a method for deep cloning. The most famous for me is lodash
import { cloneDeep } from "lodash";
const car1 = {
doors: 4,
color: "blue",
specs: {
speed: 100,
longitude: 300,
},
paint: function (newColor) {
this.color = newColor;
},
};
const car2 = cloneDeep(car1);
console.log(car2); //{ doors: 4, color: 'blue', specs: { speed: 100, longitude: 100}, paint: f };
console.log(car1); //{ doors: 4, color: 'blue', specs: { speed: 100, longitude: 100}, paint: f }; ✅