Each rectangle in the following diagrams denotes an object.
const obj = { a: {} }
is creating the object { a: {} }
in memory and assigns its reference to the variable obj
.

let aOfObj = obj.a
is assigning the reference of the inner object a
to the variable aOfObj
.

Since aOfObj
and obj.a
are referencing the same object, altering the object referenced by aOfObj
will be reflected on obj.a
too, because they are the same object.

Now when you do aOfObj = {}
, you are creating a new object (in memory) and assigning its reference to aOfObj
, so obj.a
and aOfObj
points to different objects.

Note:
Both variables and objects are stored in memory. The variables (everything on the left side above) are stored on the stack, whereas the objects (everything on the right above) are stored on the heap.
When working with primitive values (like numbers, strings, ...), the variable is stored on the stack, and its value is the primitive value itself. For example: let n = 5;
is creating a variable n
on the stack and sets its value to the literal number 5
.
When working with objects (objects, arrays, instances of classes, ...), the variable is stored on the stack, whereas the object is stored on the heap (because the stack is smaller) and the reference (the address of that object in memory) is stored as the value of the variable on the stack. For example: let o = {}
is creating the variable o
on the stack and the object {}
on the heap and set the value of o
on the stack to the address of that object which is a number (eventually keeping the stack smaller).
In javascript, unlike some other languages, the variables themselves can't be referenced, only values that are objects can, and that's why javascript is not a pass-by-reference language.