Passing by value vs. passing by reference

Understanding the difference between both can prevent unnecessary bugs in your codebase

Published Aug. 8, 2022

What's the difference?

Assigning things in JavaScript seems simple, but there's a little more that occurs behind the scenes that changes how assignment works. There's two ways of passing variables — by value and by reference.

Knowing when which occurs can easily be identified: passing by value occurs when dealing with any primitive data types (string, number, boolean, etc.), whereas passing by reference occurs when dealing with anything that is not a primitive data type (arrays and objects).

Passing by value

First, let's look at passing by value by creating a simple variable:


let a = 1;
        

...whenever anything is assigned in Javascript, it's allocated in memory. If we were to take a look inside the memory, it would look something like this...

Variable Value
a 1

...nothing unexpected. Let's add more to our code...


let a = 1;
let b = a;
let b = b + 7
        

...b is assigned the value of a, which is 1. Then, we add 7 to b. Let's look at the memory...

Variable Value
a 1
b 8

...wait, how come a didn't change if we assigned it to b and then added 7? Well, the 1 in a and the 1 in b are two completely separate values. They don't share the same piece of memory, so therefore, a isn't mutated when we add 7 to b.

Passing by reference

In the previous example we saw that primitive data types are passed by value, so each value gets its own distinct piece of memory. Simple to understand. This time, let's play around with a non-primitive data type, more specifically, an array:


let x = [1, 2, 3];
        

...if we take a look at this array in memory, it'll look something like this...

Variable Value
x 0x01

...wait, shouldn't the value of x be [1, 2, 3]? Well, yes, but it doesn't get the value directly like primitive data types do. Instead, the value is a reference to an address allocated in memory which holds the value, like so...

Address Value
0x01 [1, 2, 3]

...now what if we try to duplicate and mutate the array like in the previous example...


let x = [1, 2, 3];
let y = x;
y.push(4);
        

...let's have a look at the memory...

Variable Value
x 0x01
y 0x01

...this time, they both reference the same memory address; because of this, the changes made to y will also be applied to x...

Address Value
0x01 [1, 2, 3, 4]

console.log(x);
// [1, 2, 3, 4]

console.log(y);
// [1, 2, 3, 4]
        

...as you might guess, this can present a lot of confusing bugs if you don't understand how passing works. If you try to change one variable, it might completely change another as well.

What if we duplicate the array again, but this time we completely overwrite it afterwards? Let's have a look:


let x = [1, 2, 3];
let y = x;
y = [4, 5, 6];
        

...this time, the variable is overwritten entirely, so a completely new memory address is allocated...

Variable Value
x 0x01
y 0x02

...and each holds their own value...

Address Value
0x01 [1, 2, 3]
0x02 [4, 5, 6]

...since each value has its own memory address, both x or y can be modified without affecting one another.

To prove this concept even further, I'll use the equality operator in order to compare two arrays:


let x = [1, 2, 3]; // 0x01
let y = [1, 2, 3]; // 0x02

x == y // false
x === y // false
        

...in this example, I've created two variables that hold the same value. Despite this, they both return as false when compared with both equality operators (remember, == only checks for value equality, whereas === checks for value equality AND data type equality). This occurs because the values being compared are the memory addresses, not the actual values. Since the memory addresses are completely different, the comparison outputs to false.

To output to true, both variables must share the same memory address, like so:


let x = [1, 2, 3]; // 0x01
let y = x; // 0x01

x == y // true
x === y // true
        

...both x and y share the same memory address of 0x01, so this returns true.

Understanding whether something is passed by value or passed by reference is incredibly important. It'll help prevent a lot of weird bugs down the road, and it's helpful to know when mutating or duplicating pieces of data. Remember, passing by value occurs when dealing with primitive data types, and passing by reference occurs when dealing with arrays and objects.