Overview
JavaScript is becoming ever increasingly more popular as time goes by. While JavaScript has many advantages, it also has many interesting quirks or nuances that can catch out new beginners.
In this post I’ll show you how to deep clone a JavaScript object.
Problem
Okay … before we go any further … lets take a step back and understand the problem at hand.
Objects in JavaScript are passed by reference, meaning that any object returned by a function will point to the same memory reference as the original object. Therefore if the caller of the function modifies the returned object, they will actually be changing the original source object.
To demonstrate this quirk we have some sample code below. The GetAllEmployees function will firstly return an array of employees and will then add a new employee item onto that returned array.
let employeesCache = [{id: 1, name: 'John Smith'}];
function getAllEmployees() {
return employeesCache; // return the same object
}
function main() {
console.log('Fetching all employees ...');
let employees = getAllEmployees();
console.log(`Before: \n ${JSON.stringify(employeesCache)}`);
console.log('Adding an item to the array ...');
let employee = employees.push({id: 2, name: 'Adam Ant'});
console.log('Lets fetch all employees again ...');
let employeesAfterPop = getAllEmployees();
console.log(`After: \n ${JSON.stringify(employeesCache)}`);
console.log('The list of employees has changed');
}
main();
Running the above code will show the following console output. Most notably, you will notice that the original source array has been changed after an item was added to the array. This is because the GetAllEmployees function returns a memory reference to the original source object, instead of cloning it.
Fetching all employees ...
Before: [{"id":1,"name":"John Smith"}]
Adding an item to the array ...
Lets fetch all employees again ...
After: [{"id":1,"name":"John Smith"},{"id":2,"name":"Adam Ant"}]
The list of employees has changed
Solution
So what if we need to return an object by value rather than by reference (aka deep clone the source object), meaning that we will return a new object instance each time from the function.
Why might we do this? As an example, let’s say we have a web application that is fetching data from an API. We may want to cache the fetched data in memory to prevent unnecessary calls to the API. In this case, we will want to return a copy of the cached data from a central caching service, however, we don’t want this cached data to be accidentally manipulated by the consumer of the cached data.
The below code demonstrates how you can deep clone a javascript object. The getAllEmployees function uses the JSON.parse and JSON.stringify functions to achieve this.
let employeesCache = [{id: 1, name: 'John Smith'}];
function getAllEmployees() {
return JSON.parse(JSON.stringify(employeesCache)); // return a new object instance
}
function main() {
console.log('Fetching all employees ...');
let employees = getAllEmployees();
console.log(`Before: \n ${JSON.stringify(employeesCache)}`);
console.log('Add an item to the array ...');
let employee = employees.push({id: 2, name: 'Adam Ant'});
console.log('Lets fetch all employees again ...');
let employeesAfterPop = getAllEmployees();
console.log(`After: \n ${JSON.stringify(employeesCache)}`);
console.log('The list of employees has NOT changed');
}
main();
The above code will return the following output.
Fetching all employees ...
Before: [{"id":1,"name":"John Smith"}]
Add an item to the array ...
Lets fetch all employees again ...
After: [{"id":1,"name":"John Smith"}]
The list of employees has NOT changed
Final Thoughts
Well, I hope this article has helped you. If you have found other ways to deep clone a Javascript object. Feel free to post the solution below to help others out there.
- Solved: Build Errors Not Showning in VS 2022 - 21st November 2024
- How To: Configure VSCode to Trust Self-Signed Certs - 16th August 2024
- Solved: GitHub Actions – HTTP 403: Resource not accessible by integration - 13th June 2024
Leave a Reply