One of the fundamental differences of objects versus primitives is that objects are stored and copied “by reference”, whereas primitive values: strings, numbers, booleans, etc – are always copied “as a whole value”.
That’s easy to understand if we look a bit under the hood of what happens when we copy a value.
Let’s start with a primitive, such as a string.
Here we put a copy of message
into phrase
:
let message = "Hello!";
let phrase = message;
As a result we have two independent variables, each one storing the string "Hello!"
.
A variable assigned to an object stores not the object itself, but its “address in memory” – in other words “a reference” to it.
let user = {
name: "John"
};
When an object variable is copied, the reference is copied, but the object itself is not duplicated.
let user = { name: "John" };
let admin = user; // copy the reference
We can use either variable to access the object and modify its content
let user = { name: 'John' };
let admin = user;
admin.name = 'Pete'; // changed by the "admin" reference
alert(user.name); // 'Pete', changes are seen from the "user" reference
It’s as if we had a cabinet with two keys and used one of them (admin
) to get into it and make changes. Then, if we later use another key (user
), we are still opening the same cabinet and can access the changed contents.
Comparison by reference
Two objects are equal only if they are the same object.
For instance, here a
and b
reference the same object, thus they are equal:
let a = {};
let b = a; // copy the reference
alert( a == b ); // true, both variables reference the same object
alert( a === b ); // true
And here two independent objects are not equal, even though they look alike (both are empty):
let a = {};
let b = {}; // two independent objects
alert( a == b ); // false
For comparisons like obj1 > obj2
or for a comparison against a primitive obj == 5
, objects are converted to primitives. We’ll study how object conversions work very soon, but to tell the truth, such comparisons are needed very rarely – usually they appear as a result of a programming mistake.
Const objects can be modified
An important side effect of storing objects as references is that an object declared as const
can be modified.
const user = {
name: "John"
};
user.name = "Pete"; // (*)
alert(user.name); // Pete
It might seem that the line (*)
would cause an error, but it does not. The value of user
is constant, it must always reference the same object, but properties of that object are free to change.
In other words, the const user
gives an error only if we try to set user=...
as a whole.
That said, if we really need to make constant object properties, it’s also possible, but using totally different methods. We’ll mention that in the chapter Property flags and descriptors.
Reference
JAVASCRIPT.INFO