The concept of mutability and immutability in JavaScript is essential to understand to avoid errors.
You would often hear the most seasoned react developers suggest using the spread operator to copy an array instead of simply assigning it to a new variable. This has to do with specific data types being a reference type in JavaScript, hence being mutable. The concept of mutability and immutability in JavaScript is essential to understand to avoid errors. Let’s dive deeper into the idea of mutability vs. immutability in JavaScript.
Primitive Types Vs. Reference Types
The data assigned to a JavaScript variable can be of two types, the primitive type and the reference type. There is a difference in how JavaScript treats these two data types. To know how they are treated differently, let’s first understand the difference between primitive and reference types.
- undefined
- null
- boolean
- number
- string
- symbol
Reference Types
Reference types are not simple atomic values but are objects that are made up of multiple properties assigned to them. They are stored as a reference in memory and not as independent values assigned to variables. There are three reference types in JavaScript:
- objects
- arrays
- functions
Memory Utilization
How primitive types and reference types are stored in the memory is the basis of how they are different from each other. Let’s look at a few examples and try to understand how they utilize memory differently.
Primitive Types
As highlighted earlier, primitive types are stored as a single atomic value assigned to a variable in the memory. Let’s see this example:
let name = "john";
let name2 = name;
Looking at the above example, I created a variable name and assigned it a
value john
. Now JavaScript will save this as a single atomic value in the
memory. Now, if i create a new variable name2
and assign it a value of the
variable name
JavaScript will go ahead and create a new space in the memory
and allocate the same value of the variable name and assign it to the
variable name2
. The new value assigned to the variable name2
, is entirely
separate from the variable name
and does not have any reference to it
whatsoever.
Reference Types
Reference values are objects stored in memory and references to objects instead of dedicated places in memory, unlike primitive types. Let’s look at the following example to understand better how the reference types are saved in memory by JavaScript.
let person = {
name: "john",
age: 22,
};
let person2 = person;
Let’s just declared a variable called person
which will contain an object
containing the name
and the age
of the person
object. Now I will go ahead
and create another variable named person2
and assign it the same person
object. This is where things start getting different as compared to the
primitive types. In this case, JavaScript will save the person2
object simply
as a reference to the person
object.
If you look at this image, you will realize that JavaScript here is actually pointing to the same object in the memory. Though it has created a new variable, as a value, that variable just is referring to the same person object that we created previously.
Immutability and Mutability
Since we are now clear with the primitive and reference types in JavaScript, we can easily understand the concept of mutability and immutability in JavaScript. Mutable can be changed or added to where immutable means something that cannot be changed or added.
Primitive Types
Primitive values in JavaScript cannot have anything added upon to them, they can only be re-assigned, and hence all primitive values in JavaScript are immutable. Let see this with an example.
let name = "john";
let name2 = name;
console.log(name);
console.log(name2);
/*
* john
* john
*/
let name2 = "doe";
console.log(name);
console.log(name2);
/*
* john
* doe
*/
Extending our previous example of primitive types, let’s print the values of
both our variables, i.e. name and name2
to the console and see what we get. As
expected, both the variable return the value john
. Now let’s reassign name2
to doe
and then again print the values of both the variables to the console.
Now you see that the value of only name2
was re-assigned by JavaScript
to doe
, but the variable name
did not change. This show’s that JavaScript
treats these 2 variables separately, although name2
was originally copied from
the variable name
. This proves that the primitive values in JavaScript, in
this case, strings, are immutable.
Reference Types
Let’s try to replicate the same example for reference types as well. Picking up
from our previous example, let’s print the values of both person
and person2
objects to the console and see what we get.
let person = {
name: "john",
age: 22,
};
let person2 = person;
console.log(person);
console.log(person2);
/*
* {
* name: 'john',
* age: 22,
* }
*
* {
* name: 'john',
* age: 22,
* }
*/
We see two objects printed on the console with the same properties. Now I will
change one of the properties of the person2
object and print them to the
console again.
let person2;
name = "doe";
console.log(person);
console.log(person2);
/*
* {
* name: 'doe',
* age: 22,
* }
*
* {
* name: 'doe',
* age: 22,
* }
*/
You see that JavaScript has changed person as well as person2
. This is because
the person2
object was created by referencing the person
object. With
reference types, JavaScript creates a reference to the same object, and the
object remains mutable. Since the object is mutable, it can be changed, or a new
property can be added.
The Spread Operator
The spread operator was introduced in ES6 (more information on ES6) and lets you copy your objects safely and create a new instance of the object instead of merely referencing the previous object. Let’s look at the same example and see how we can copy an object and save a new instance of the variable's object.
let person = {
name: "john",
age: 22,
};
let person2 = { ...person };
let person2 = (name = "doe");
console.log(person);
console.log(person2);
/*
* {
* name: 'john',
* age: 22,
* }
*
* {
* name: 'doe',
* age: 22,
* }
*/
Let’s take the same person
object, and instead of assigning it directly to a
variable this time, let’s use the spread operator to copy it. The spread
operator can be used by prefixing three dots …
in front of the object that you
want to copy and encapsulate it using the literal object syntax. This way,
JavaScript creates a new object and stores it in the variable person2
. Let’s
try to change one of the properties of person2
. I will change the name
to doe
. Now let’s print both the object to the console and see what we get.
You see, this time, we only changed the name property of the person2
object
and not the person
object. This is because the person2
was created and saved
as a new object using the spread operator and not as a reference to the person
object.
What Can You Do Next 🙏😊
If you liked the article, consider subscribing to Cloudaffle, my YouTube Channel, where I keep posting in-depth tutorials and all edutainment stuff for ssoftware developers.