Understand Pass by Reference in JavaScript
Published: 2023-08-07 17:31:32

In JavaScript, primitives are **passed by value**, while objects are **passed by reference**. As someone who is still new to the language, this is a concept I found myself struggling with. If you’re a newbie like me, I hope you already know what an object is. Here is an object:

```
const colors = {
Blue: “#f00”,
Orange: “f60”
};

```
And objects can hold any number of primitives. Technically, there are six primitives (Boolean, number, null, undefined, string, and symbol) though symbol is still a new feature of the language and is limited to more advanced applications.

Let’s quickly demonstrate this whole pass by value vs pass by reference concept:

`const a = 1` means that the number **1** is copied, and if we were to create another variable and also assign it 1. For example, `const b = 1`. The number 1 would still be 1 anywhere. And we can confirm this below: 

```
const a =  1;
const b = 1;
console.log (a === b);
```
We’ll get **true**. This is because 1 is a primitive, and primitives have the same value; therefore, JavaScript recognizes them as the same copied piece of data. Another way of saying this is that primitive values are **passed by value**. While this might seem obvious, this is not the case with objects.

**_What about objects?_**

When we have an empty object (`{}`) and assign it to object1 so that we have `object1 = {}`, what object1 receives is not a **copy of** `{}`, unlike the primitive example that we’ve seen above. It gets what is known as a **reference** instead. If we were to create another empty object (`{}`) and store it in another variable object2 (`object2 = {}`), we would automatically expect the two to be the same because we’ve created them the same way. However, if we compare the two:
 
```
console.log (object1 === object2)
```
we get **false**. Why? This is because of the nature of objects and what we can do to them (we can dynamically add properties to objects). Unlike objects, primitive values are immutable, and we cannot change their properties. Therefore, any primitive value is not unique and cannot differ from another primitive of the same data type. In other words, another primitive like the Boolean true cannot be different from any other instance of true. `true === true`.

However, when JavaScript makes a new object, it makes a **unique value**, which is different from any other object because it is stored in a completely different place in memory. JavaScript treats this value differently due to its ability to have its own custom properties (properties can be different for objects to manage completely different sets of primitives).  Therefore, anytime we pass an object to a variable, it just holds a reference to it. 

Up to this point, this may have **‘clicked’** for some people, but I was having difficulty wrapping my head around this whole pass by reference concept. It wasn’t ‘clicking’ for me, and I needed a mental image of what was happening. 

What happens when I feel **stuck** is I always try to check out other people’s explanations of the same concept, and that is how I stumbled upon this [video](https://www.youtube.com/shorts/rbPd3OpeNeU) by Zoref Code on YouTube that illustrates this concept using arrows.

Now, let’s start over again, but with the help of arrows.

## Pass by Value
Let’s say we have a variable a that is assigned to 1, `let a = 1` and another variable b that is assigned to a (`let b = a`). Here is our code: 


![let a = 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s7qmwuv9bmtg84e07msz.png)

Because a is equivalent to 1, the arrow points at 1, but we have another variable, b, which equals a (`let b = a`). Therefore, b will look for the value of a (**which points to 1**), and b will now be equal to 1, as shown below: 


![Each arrow has been marked with 1, 2, and 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/77325j6c9we9a8v4bnhl.png)

To make this easier to understand, I’ve marked each arrow with **_1_**, **_2_**, and **_3_**. We start from arrow 1, which tells us that a is equivalent to 1. Then, when we introduce the second variable, `let b = a`, b **will look** for the value of a (**using arrow 2**), and when it finds that the value of a is 1, b will also form a new arrow that will also point at 1. The new arrow is **arrow 3**.

When we update the value of a to 2 (`a = 2`), a will now point to 2 while b will still be pointing to 1 as shown below:


![Passed by value](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we4k0vws6ownxrgx4buj.png)

Now, take a pause and think about what just happened. We updated a to 2, and that’s it!! **Arrow 1 is pointing at 2** because we updated a to 2. We just changed the value of a from 1 to 2, so **arrow 2 won’t have any effect** here. Arrow 2 won’t need to look for the value of a because the value of b remains unchanged and is still 1. This is why **arrow 3 is still pointing at 1**.

In more nuanced terms, when you assign a variable like `let a = 1`, part of your computer’s Random Access Memory (RAM) will hold that value, which is 1 in this case. The value 1 is now stored, and it is kept at a given location in your memory. **Passing by value** means that the thing that is stored in the location, in this case, 1, is the one that is passed. `let b = a` means we’ve created a new variable called b (**that has its own location in memory**) with the value 1.

When we re-assign a to 2, this changes the value of a, but not b, because a and b are **two separate locations in memory**. We can even `console.log` their values, and we’ll find that a is 2 while b is 1. 


![console.log both a and b](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9fki8zzk1vsweb6wta3o.png)

## Pass by Reference

Let’s say we have a variable a that is equivalent to `{id: 1}`. This means that a will point at `{id: 1}` as shown below. We’ve used arrow 1 to establish this relationship:


![let a = {id:1}](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b30ndgeyowyd1t3dthx8.png)

Just like in the previous example, if we assign a to another variable b (`let b = a`), b will look for a (**using arrow 2**), and when it finds that a is pointing at `{id: 1}`, b will also point at `{id: 1}`, **using arrow 3**.

![Pass by reference](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qli63asaxxqfmebsv7k6.png)

Look closely; you’ll notice that **arrow 3** runs directly from b to `{id:1}`. This is pass by reference. JavaScript has created a new association (pointer) from b to whatever a points at, as shown above (at this point, we now have a and b both pointing at the same value, which is `{id:1}`).

Now, let’s take things up a notch and update a using `a.id = 2`. a will point at `{id: 2}`. But remember, b also had an arrow pointing at `{id:1}` **that is now updated to `{id:2}`**. This means that b will also be updated to `{id:2}`. Again, you can `console.log` their values to prove that it's 2 for both cases.


![console.log a and b](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ycnt3y9aojvtltye000.png)

In more nuanced terms, when we **pass by reference**, it is the location in memory that we pass. The `b = a` statement means that b points to the same location in memory that a does (we’ve made b have the same memory location as a). Therefore, changing a will also change b. Another way to think of it is that if an object is assigned to a variable (like `let a = {id:1}`), it’s not copied over when we use the equals sign. This means it’s not passed by value.

Let’s look at another example and use an empty object. `const object1 = {}`, then let’s create object2 and assign it to object1 `object2 = object1`

![Assign empty object to a variable](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dclvufs8sdcl4i6ddzy1.png)
Just as we have already explained earlier, when `{}` is assigned to object1, what object1 receives is not a copy of `{}`, but what’s known as a reference. object1 gets a reference to `{}`. If we update object2 using `object2.a = 1`, then compare the two, we get **true**:

![object2 = object1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38gjbu9z96s0bkej5nfg.png)
This means that object2 was also updated. Both object1 and object2 give the same output, which is `{a:1}`. Because JavaScript did not pass a copy of object1 during the assignment, but just a reference to `{}`, we were able to update both variables (object1 and object2). 

In most cases, this may not be what we want as developers; therefore, we must fix this default behavior of **passing by reference** that occurs in objects. This feature has made it necessary for developers to learn how to update objects to avoid surprises and make their code less error-prone and more reliable.