Javascript Clone Object | Deep copy object Javascript
In this post you will learn how how to copy objects inside Javascript and how to implement deep copy (or deep clone) method on your own.
The first question here that you for sure want to ask is "Why do we need a copy of our object?".
And typically people write something like this
const a = {b: 1}
const newA = a
newA.c = 2
console.log(a, newA)
The idea is that we copy an a
to newA
and then modify our newA
. This code won't work and both object are changed.
It happens because objects are assigned by reference and not by value. Both this objects are referencing the same data in memory.
The typical solution to this problem is to use Object.assign or spread.
const a = {b: 1}
const newA = {...a, c: 2}
console.log(a, newA)
This will work fine and we will change only newA
now. With using of spread operator we created a completely new object and now it is safe and correct.
In the same way you can use Object.assign
.
const a = {b: 1}
const newA = Object.assign({}, a, {c: 2})
console.log(a, newA)
It is an older approach but it works just as well.
Deep copy
Now we must talk about deep copy inside Javascript. It means that we want to copy a nested object.
const a = {b: {c: 2}}
const newA = {...a, d:2}
newA.b.f = 3
We used here spread but actually we will get f=3
in both objects simultaneously.
Spread it not working correctly with nested objects because nested properties will be referenced again
This is why we must find another approach.
Json stringify
And the easiest approach might sound a little bit hacky.
const a = {b: {c: 2}}
const newA = JSON.parse(JSON.stringify(a))
newA.b.f = 3
Here we used stringify and parse which generates a string from object which we parse then back to JSON. It will essentially create a new nested object.
And here you might ask "It looks like awesome idea. Why we don't use it everywhere?". The main problem is that if you have a huge object or you have not normal object or array then this method will break. For example if you have functions or DOM elements inside then it won't work.
It is a good solution for simple constructions but it is much better to have a specific method that does deep copy.
Using a library
The best possible variant for deep copy is using a library. Let's put in our index.html a script for lodash library.
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
If you don't now what is Lodash it's a super popular library for data transformations. You have hundred of different functions inside. And one of this functions is called cloneDeep
. This is why here instead of JSON.stringify
we can use a library.
const a = {b: {c: 2}}
const newA = _.cloneDeep(a)
newA.b.f = 3
As you can see in browser it works exactly like before but we used a library and this code won't break with big amount of data.
If we are talking about production project I highly recommend you to use this function and you are good to go.
But you must use it only when you have nested objects or arrays. It is much slower than using spread to copy not nested data. This is why I don't recommend you to put it in every single case.
Custom deep copy implementation
But obviously to understand how deep copy function works we must implement it on our own. Here I want to write a function which will implement a deep copy for arrays and objects.
const clone = (input) => {
if (input === null || typeof input !== "object") {
return input;
}
};
Here we created clone
function where we can throw any data. And we check inside that if it is not array or object we simply return new value. It is totally fine as we get new value.
const clone = (input) => {
if (input === null || typeof input !== "object") {
return input;
}
const initialOutput = Array.isArray(input) ? [] : {};
return Object.keys(input).reduce((acc, key) => {
acc[key] = clone(input[key]);
return acc;
}, initialOutput);
};
Here we created initialOutput
for either array or object depending what we passed inside. After this we used reduce
function on Object.keys
which gives us keys of the object or indexes of the array. Then we go through every single key and call clone
function recursively. Which actually means it doesn't matter how deep our nesting is, we will copy every single property.
const a = {b: {c: 2}}
const newA = clone(a)
newA.b.f = 3
As you can see in browser it works exactly like a method from Lodash.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done