Table of Contents
Introduction
Good day, folks!
Often times we want to create copies of variables for different purposes. There can be two different kinds of copies created - Shallow copy and Deep copy. We commonly encounter shallow copy and deep copy understanding and differences during interviews. So, let's go over the terminologies and related examples.
Shallow Copy
Shallow copy method creates a copy where the source and the copied variable reference remain the same. This means that modifications made in one place would affect both places.
Here's an example to get a better understanding:
const first_person = {
name: "Jack",
age: 24,
}
const second_person = first_person;
second_person.age = 25;
console.log(first_person.age); // output: 25
console.log(second_person.age); // output: 25
Changing the age property value of second_person
object, changes the first_person
object's age property too.
Now let's look at another example:
const first_person = {
name: "Jack",
age: 24
};
let second_person = first_person;
second_person = {
name: "Jack",
age: 23
};
console.log(first_person.age); // Output: 24
console.log(second_person.age); // Output: 23
Uh, what happened here? 🤔 Why aren't the values same?
Well, here we are not changing the values of a specific property rather we are assigning a new object.
Deep Copy
Deep copy method creates a copy where the source and the copied variable reference are completely different. This means that modifications made in one place would only affect the variable where we are making a change.
Now let's look at the examples:
If the objects/arrays are not nested, then we can achieve deep copy by using
Spread (...) operator
Using the spread syntax, we can create a deep copy if there is no nesting.
const first_person = {
name: "Jack",
age: 24,
}
const second_person = { ...first_person };
second_person.age = 25;
console.log(first_person.age); // output: 24
console.log(second_person.age); // output: 25
Let's take a look when there is nesting.
const first_person = {
name: "Jack",
age: 24,
address: {
apartment: "A",
city: "London"
}
};
const second_person = { ...first_person };
second_person.age = 25;
second_person.address.apartment = "N";
console.log(first_person.address.apartment); // output: N
console.log(second_person.address.apartment); // output: N
In case of nesting, the spread operator creates a shallow copy.
If the objects/arrays are nested, then we can achieve deep copy by using
JSON.parse() and JSON.stringify()
const first_person = {
name: "Jack",
age: 24,
address: {
apartment: "A",
city: "London"
}
};
const second_person = JSON.parse(JSON.stringify(first_person));
second_person.age = 25;
second_person.address.apartment = "N";
console.log(first_person);
console.log(second_person);
Combining these two creates a deep copy even when there is nesting involved.
Summary
- Shallow copy method creates a copy where the source and the copied variable reference remain the same. Changing one, would change the other as well.
- Deep copy method creates a copy where the source and the copied variable reference are entirely different. Changing one, would not affect the other one.
- Common methods like Array.concat(), Array.from(), Object.assign(), etc creates a shallow copy.
- Spread(...) operator, creates a deep copy when there is no nesting.
- One of the ways to create a deep copy is by using JSON.parse() and JSON.stringify().
Top comments (15)
I believe you misunderstood those terms. First of all, there are 3 concepts, not two:
Also, you shouldn't use
JSON.parse/stringify
to deep copy objects. It's neither the safest way nor should it be recommended. You'll lose some data (e.g. Date, Function, RegExp), have a high chance of errors (e.g. using Symbols, recursive references, etc.) and have a rather bad performance penalty compared tostructuredClone
.Thanks for pointing it out! I probably should have just clarified a bit more.
I have edited it and hope it's a little better now.
Thanks again!
You probably mix things up here or maybe I understood it wrong.
Shallow copies are non-reference copies but only for the first level in case of non-primitive types like object or arrays.
JSON.parse(JSON.stringify(obj))
is also not the ultimate solution because it fails for some types which cannot be parsed like NaN or Infinity [ref]And you list the spread operator under the headline deep copy but it's also a shallow copy.
I guess JS's way of dealing with objects so messy. Why doesn't it have any explicit function like Python's "deepcopy"? Relentlessly nuisances come up and people have to make workarounds like ones mentioned here. Gross...!
check this out :) developer.mozilla.org/en-US/docs/W...
Oh, I gotta check this out thanks!
I sometimes used the stringify and parse method too. Underscore and lodash library have deepclone methods.
Once I implementes a kind of ORM. it had query batching. and I wanted to every client to receive a copy if the data. I implemented my own deepclone. It was much faster than underscode. the reason is not that I am so smart, but that my cloneFunction did not need to handle circular objects.
i consider stringify amd parse as quick and dirty, but totally valid option, because you can change the implemebtation down the road, when you get new requirements, such as more performance, more datatypes, or just make it look more professional.😉
Thank you. This helps me understand a problem I ran into a while back. As someone who’s not really versed in JS, my situation was frustrating. I should take the time and study JS starting from its foundation. Do you recommend any good books/sites?
Absolutely! It would be best if you spent some time with JS before moving to any framework. Build small projects, read basic stuff off MDN, and you are good to go!
Well Articulate Aditi, Learn a lot
Learnt something really important and cool today. Knew the spread operator thing but didn't know the technical name and reason. Thank you for this !! Very simply explained.
Thank you, Maitra! Glad, it was helpful! :)
I think, depending on what you want to achieve, you should create your own copy function. This way you can decide for every reference, if it has to be cloned (new object) or be kept (as a reference).
This is very insightful. Got surprised after seeing how spread operator can affect in two different ways.
Thank you very much Aditi! Can you point some resources which you've used to write this super informative article.
That was so great 👌