I know that the assignment of one variable to another is done by shared reference so that when you set var c = b; and then you do some change change to c such as c.cool = 'new'; then b gets affected as well. console.log(b.cool); // new
However, coming to Javascript from different programming languages, I remember there is an error prone ‘gotcha’ when using the spread syntax var c = {…b}. Can somebody clarify this ‘gotcha’ and any nuances to keep track of?
TLDR; When
var b = { …an object of your choice …};
the subsequent assignment ofvar c = b;
is an assignment by shared reference. You can think of bothb
andc
as pointing to the same thing in memory; things that changec
will changeb
and vice-versa, changeb
and it will changec
.Assignment by spread syntax
var c = {...b}
means something slightly more complicated. Specifically, the behavior is different is for top-level properties and for nested properties. For top-level properties, there is a deep copy (leavingc
andb
are independent) but for nested-properties, there is a shallow copy (changes toc
andb
affect the other.) (SO DEEP COPY FOR TOP-LEVEL PROPERTIES, SHALLOW COPY FOR NESTED-PROPERTIES).So what are SHALLOW COPY vs. DEEP COPY?
From free code camp:
So let’s look at an example and change both a top-level property and then a nested property. And remember, you can change
c
and see how to affectsb
, but you can also changeb
and see how it changesc
.REGULAR ASSIGNMENT
So far ^ that’s pretty consistent, anything you change in
c
gets reflected inb
.However, the following is the “gotcha” of spread syntax that ... well ... does not feel as clean from a programming language perspective, and that can be a bit user error prone.
When assigning a variable via spread syntax, a deep copy is made at the top-level properties, meaning you get NEW copies of top-level properties but only a shallow copy (SHARED REFERENCES) for any nested properties. Here is are example that shows the difference in how top-level vs nested properties are treated.
SPREAD SYNTAX
ADDING A COMPLETELY NEW NESTED PROPERTY
What happens you later ADD a completely new nested property to one or the other?
REGULAR ASSIGNMENT(ADDING A COMPLETELY NEW NESTED PROPERTY)
SPREAD SYNTAX (ADDING A COMPLETELY NEW NESTED PROPERTY)
COMPLICATING THINGS EVEN MORE - PASS-BY-VALUE (PRIMITIVE TYPES)
Just to make things slightly more confusing.
The above paradigm really only works when
b
is an object. Ifb
is a primitive value (number, string, boolean, null, undefined, symbol), then it’s called ‘assign-by-value’ and the behavior of var c = b; means something different.c
gets its own set of values. The examples below show the difference:Referenced:
https://www.freecodecamp.org/news/javascript-comparison-operators-how-to-compare-objects-for-equality-in-js/
https://javascript.info/object-copy
https://www.freecodecamp.org/news/javascript-assigning-values-vs-assigning-references/
https://medium.com/@naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600#:~:text=On%20variable%20assignment%2C%20the%20scalar,at%20other%20variables%20or%20references