A lot of times we are thinking to make a copy of a JavaScript object, why? Because, we just want to reuse the assignments we already did for that object, and avoid repetitions. We are trying to change few things in the new object and reuse it. This is our primary assumption.
const user1 = {
name: "Linus Torvalds",
age: 14,
status: true,
is_student: true,
is_passed: true
};
console.log(user1); // {name: 'John Doe', status: true, is_student: true, is_passed: true}
Suppose I want to reuse same details from above mentioned object, and just want to change some details like name. So we will do like this.
const user2 = user1;
user2.name = "Steve Jobs";
console.log(user2);
// output: // {name: 'Steve Jobs', status: true, is_student: true, is_passed: true}
But things don’t work like that. Why? Because the objects works on the basis of references. The above implementation will change the values of first object as well and result as follows:
console.log(user1.name) // output: Steve Jobs
// But we are expecting that the output will be: Linus Torvalds
So, to avoid this kind of situations, we have some methods where we can create a copy of object without touching its parent object i.e. it cut down the references with previous object.
There are 4 methods
- Spread Method
- Object.assign() Method
- JSON.parse() Method
- The Ultimate Method – structuredClone()
And one more “The Ultimate Method”.
Lets have a look all 4 methods, one by one.
Spread Method
The spread operator or you can call it triple dots operator was introduced in ES6. Its spread values into an object. Lets see the same example.
const user1 = {
name: "Linus Torvalds",
age: 14,
status: true,
is_student: true,
is_passed: true
};
// clone using spread operator
let user2 = { ...user1 };
console.log(user2); // {name: 'Linus Torvalds', status: true, is_student: true, is_passed: true}
// changing the value of cloneUser
user2.name = "Steve Jobs"
console.log(user2.name); // 'Steve Jobs'
console.log(user2); // {name: 'Steave Jobs', status: true, is_student: true, is_passed: true}
console.log(user1); // {name: 'Linus Torvalds', status: true, is_student: true, is_passed: true}
If you notice in above code, the last two console.log statements, they are printing the correct data. Because, the objects are not referenced now, and their will be no change in parent when we did changes in child object.
Object.assign() Method
Its an alternative to the spread operator is the Object.assign() method. You use this method to copy the values and properties from one or more source objects to a target object.
// Declaring Object
const user1 = {
name: "Linus Torvalds",
age: 14,
status: true,
is_student: true,
is_passed: true
};
// Assign user1 properties to an empty object and assign it to user2.
const user2 = Object.assign({}, user1);
console.log(user2); // {name: 'Linus Torvalds', age: 14, status: true, is_student: true, is_passed:true}
In above example, now user2 is having all the properties of user1, without any object references.
// Declaring Object
const user1 = {
name: "Linus Torvalds",
age: 14,
status: true,
is_student: true,
is_passed: true
};
// Assign user1 properties to an empty object and assign it to user2.
let user2 = Object.assign({}, user1);
user2.name = 'Steve Jobs';
console.log(user2); // {name: 'Steve Jobs', age: 14, status: true, is_student: true, is_passed:true}
console.log(user1); // {name: 'Linus Torvalds', age: 14, status: true, is_student: true, is_passed:true}
Important: Object.assign() make a shallow copy of the object, deeper objects are still referenced. Lets see the following example.
// Declaring Object
const user1 = {
name: "Linus Torvalds",
age: 14,
address: {
country: "India",
city: "Pune"
}
};
// Assign user1 properties to an empty object and assign it to user2.
let user2 = Object.assign({}, user1);
user2.name = 'Steve Jobs';
user2.address.country = "US"
console.log(user2); // {name: 'Steve Jobs', age: 14, address: { country: 'US', city: 'Pune' }}
console.log(user1); // {name: 'Linus Torvalds', age: 14, address: { country: 'US', city: 'Pune' }}
// "name" property is not referenced, but "country" property is still referenced.
JSON.parse() method:
We can make a deep clone of the object with JSON.parse() method along with JSON.stringify() method.
// Declaring Object
const user1 = {
name: "Linus Torvalds",
age: 14,
address: {
country: "India",
city: "Pune"
}
};
// Assign user1 properties to an empty object and assign it to user2.
let user2 = JSON.parse(JSON.stringify(user1))
user2.name = 'Steve Jobs';
user2.address.country = "US";
console.log(user2); // {name: 'Steve Jobs', age: 14, address: { country: 'US', city: 'Pune' }}
console.log(user1); // {name: 'Linus Torvalds', age: 14, address: { country: 'India', city: 'Pune' }}
In above example, if you noticed the change of inner object address, its property named country is also dropped the reference to the previous object. The value inside new object is changed without any impact on parent object.
Note: This method deeply clone your object but with some drawbacks. It’s not working with function or symbol properties.
The Ultimate Method — structuredClone( ):
The structuredClone() method of the WorkerGlobalScope interface creates a deep copy of a given value using the structured clone algorithm.
Syntax:
structuredClone(value) structuredClone(value, options)
This method make deep copy means, it will create an exact copy of the object including internal/nested objects as well.
// Declaring Object
const original = {
name: "Linus Torvalds",
age: 14,
address: {
country: "India",
city: "Pune"
}
};
// Clone it
const clone = structuredClone(original);
clone.address.city = "Cincinati"
clone.address.country = "USA"
console.log(original);
console.log(clone);
/** OUTPUT **/
{
name: 'Linus Torvalds',
age: 14,
address: { country: 'India', city: 'Pune' }
}
{
name: 'Linus Torvalds',
age: 14,
address: { country: 'USA', city: 'Cincinati' }
}