How JavaScript works behind the scene- Primitive vrs Reference Values
Hello World, Akwaaba ๐. JavaScript allows us to work with two data types: primitive
and non-primitive
.
When you create a variable in JavaScript, it can store two types of values, a primitive
value or a reference
value.
At the end of this article, you should be able to understand how these two data types work behind the scenes.
Let's get started ๐.
Primitive vrs Reference Values
What are Primitive data type
There are seven primitive data types: string
, number
, bigint
, symbol
, boolean
, null
, and undefined
.
Primitive data types can store a single value.
All primitives are immutable meaning the values are incapable of being changed. The variable can be reassigned to a new value, but the actual value can not be changed.
To check if a value is a primitive value, you can use the typeof
next to the variable name, this will return any of the data types listed above.
Let's take a look
var name = "Emmanuel";
typeof name ; /* returns "string" */
var myNumber = 45;
typeof myNumber ; /* returns "number" */
var result = true;
typeof result; /* returns "boolean" */
What are non primitive data types
If you want to store multiple or complex values then you need to use non-primitive data types.
Object
literals, Arrays
, and functions
are basically objects or what we will call non-primitive
values.
Non-primitive
values do not have a fixed size. For instance Objects
, for example, can be of any length, arrays
can have any number of elements and a function
can contain any amount of code in its block.
Because these types do not have a fixed size, their values will not be stored directly in the memory associated with each variable. Instead, the variable stores a reference
to the value.
Confusing ๐, we dive deeper as we move along ๐ถ
Let's now take look at what happens in the JavaScript engine when it encounters these two data types.
Inside the JS Engine
The JavaScript engine is made of two parts, the call stack
and the heap
. All primitive
values are stored in the call stack
since the size of a primitive value is fixed.
However, reference
types or non-primitive
data types are stored in memory in the heap
because the size of a non-primitive
or reference
value is dynamic.
Now let's take a look at what happens when you assign either primitive
or non-primitive
value to a variable
๐
Assigning values
When you want to assign a value
to a variable
, the JS engine will check to see if the value is primitive
or non-primitive
value. If the value
is a primitive
value it will be stored in the call stack
because it does not take so much memory.
Let's now investigate what happens to primitive
values under the hood. ๐
Understanding passed by value and passed by reference.
Primitive
data types are passed byvalue
whilstnon-primitive
data types are passed byreference
.
To understand passed by value and passed by reference, we need to understand what happens when we create a variable and assign a value to it.
How primitive values work in the JS Engine
Let's use the code below and see what is happening under the hood
var x = 2;
In the above when we declare a
variable
and assign it avalue
, the JS engine creates aunique identifier then the assignment operator (=
) will allocate some space in the memory of thecall stack
and store the value2
.It then returns the location or address of the allocated memory space. Eg Ax001
The variable
x
is therefore pointing to the location or address of the allocated memory space (Ax001) and not pointing directly to the actual value of 2.As a result, if you want to access the
value
, you will need to go to the location or address in memory i.e Ax001
Copying primitive values
Let's now look at what happens when you copy a value to another variable.
Let's use the example below
var x = 2;
var y = x;
When you copy the value stored in
x
toy
, you are basically copying the allocated address in memory (i.e Ax001) to the variabley
.The variable
y
and the variablex
all point to the same address in memoryThe variable
y
does not really know about the value stored inx
it only knows of the location or address to go to find the value ofx
.
What is happening in the above
When you assign a variable that stores a primitive value to another variable, both the former and latter variables point to the same address in memory. So, if the address in memory for the x
is Ax001
then the address in memory for the y
will be Ax001
.
var x = Ax001 /* x is pointing to the allocated address of the value 2 not the value directly */
var y = x;
var y = Ax001 /*y is pointing to the same allocated address in memory */
Modify or changing the value in a variable
Let's now assume you want to modify or change the value stored in x
, will the value at y
change too?
Let's find out
x = 20;
console.log(y) ; /* 2*/
console.log(x); /* 20 */
Changing the value of
x
to20
does not change the value of the variable aty
, why?Because
primitive
values cannot be changed, the JS allocates a new address in memory (Eg. Ax002) and stores the new value there.So whiles
x
now points to the allocated address of Ax002, the variabley
still points to the previously allocated address in memory (ie Ax001).Hence if you change the
value
stored inx
to20
it will not affect thevalue
stored iny
. ๐ฑ
So what is the verdict?
We can conclude that primitive
data types when they are passed to another variable, are passed by value.
What it simply means is, instead of just assigning the value to same address or location in memory, the value
will be passed to a new location or allocated space in memory.
Reference values
Objects
are stored in the heap
of the JS Engine, the reason being, Objects
have complex values which do not have fixed sizes hence it is appropriate to store them in a place with big memory.
When we create a variable and assign a non-primitive
data type to it, the JS engine creates a unique identifier, allocates an address in memory on the call stack, but stores the actual value in the heap.
Now because we declare the variable in the 'call stack', it will allocate some address in memory and then store the value.
But wait, the value was actually stored in the heap
. So what will happen is, we will have to forward the allocated location or address to the value stored in the heap to the call stack
first.
So the variable
declared in the call stack
will point to the forwarded address or reference
address in the call stack and from the call stack
we will point to the actual value stored in the heap.
Let's break it down with some code
var user = { name: "Emmanuel", age: 34} ;
var user = # 1234; /*the object is stored in the address #1234 in the heap */
/* When the variable is declared, we will create a space in memory (location ) and store the value
But the value was stored in the heap, so the address or location of the heap will be passed to the call stack.
Meaning the user variable will point to the reference address or location
*/
Copying values to Object
Let's see what happens when we copy an object to another object
var user = {name: "Emmanuel", age: 34}
/*user points to the address #1234 in the heap */
var user2 = user /*Assign value of user to user2 */
Passing a reference value
When you assign a reference
value from one variable to another, the value stored in the variable will also be copied into the location of the new variable. As a result, the values stored in both variables all point to the address or location of the actual object stored on the heap.
So, both the user
and user2
variables, are referencing the same object
With the code above, the assignment operator, will straight ahead pass the location of the variable
user
which is#1234
to the variableuser1
.In other words, the reference of the variable
user
is passed to the variableuser1
user1
points to the same address asuser
(user1
points to#1234
as well ).
Changing or modify the value
Finally, let's take a look at what happens when you modify or change the value stored in the initial variable, user
.
In the code below, we are adding another property
country to user
var user = {name: "Emmanuel", age: 34};
var user1 = user;
user.country = "Ghana"; /* Assign a value to user object */
console.log(`Details of user`, user);
/* Details of user {name: "Emmanuel", age: 34, country: "Ghana"}*/
console.log(`Details of user1`, user1);
/* Details of user1 {name: "Emmanuel", age: 34, country: "Ghana"} */
What is happening above?
Changing or modifying the values in the
user
object, modifies the value in theuser1
object.This is happening because both
user
anduser1
all point to the sameobject
or they reference the same object in the heap.Any property that is modified in one variable, will change or modify the value in the other variable.
From the above example, we can conclude that when passing non-primitive
data types, the assignment operator directly passes the address or reference. Hence, non-primitive
data types are always passed by reference.
What this means is, whenever you are copying an object, you are pointing to the exact same value in the heap. Knowing this will avoid so many headaches when working on Object
or non-primitive
data types in JavaScript.
#Summary
In this article, we learned about the primitive
values and non-primitive
values.
There are seven primitive types:
string
,number
,bigint
,symbol
,null
, andundefined
. Primitive data types can store a single value. Primitive data types are passed by value.Object
,Arrays
andFunctions
are non-primitive data types. Non- primitive data types are passed by reference, hence they are also known asreference
values.
If you found value in this post, kindly share it on your social media channels. It will be a great reference to a code newbie. Did you find value in my post, I would love to read your comment on it. Me daa se
PS: Akwaaba and Me daa se are Ghanaian ๐ฌ๐ญ dialect meaning, Welcome and Thank you respectively
Writing with โค๏ธ from ๐ฌ๐ญ