JS


JS Traps: Pass By Value And Pass By Reference


October 1, 2025



Two worlds: primitives and objects

Let’s start with a necessary premise, just to refresh our memory. In JS, values are divided into two main categories:

The difference is not just academic: it completely changes how they are passed and what kind of side effects you can expect.




Pass by Value

Let’s start with the simplest one: pass by value. When you assign or pass a primitive, you’re actually passing a copy of its value, not the original:


pass-by-value


The variable b is assigned the value of a, but this doesn’t mean that if b is changed, the modification will also reflect on a. In fact, b receives a copy of the value of a, not the physical memory address where a’s value resides.


In practice, any changes to variables passed by value have no impact on the outer scope where they are used.




Pass by Reference

With objects, things work differently. Here you don’t copy the object, but rather the memory address where it resides.


simple-object-mutation-side-effect


Oh! I unexpectedly changed the property value of obj1 as well!!

Disgusting, right? Yes, and this is one of the reasons many developers dislike Javascript.




What’s really happening?

When we write obj2 = obj1, we are assigning obj2 a copy of the memory address of obj1:


two-varisbles-same-reference-heap



This means we are actually referring to the same object in memory, but with a different variable name. Any modification in obj1 will inevitably be reflected in obj2 regardless of the scope, and vice versa. In short, changes to objects passed by reference propagate to the outer scope.




What if we modify the object inside a function?

I’ve got bad news for you:


mutate


Even objects passed as function parameters are not safe from this problem, if their properties are directly modified inside the function.


What happens here is that inside the function we dive into the object at the passed memory address and mutate one of its values directly.


direct-mutation-heap


obj1 undergoes the direct mutation, and obj2 is also affected even though it wasn’t explicitly modified, unlike obj1.




What if we reassign the object passed as a parameter?

The situation looks similar but is fundamentally different when it comes to reassignment:


reassign



Here nothing happens to the original. Why? Inside the function you create a new object with a new address. The original one remains untouched.


new-reference


And what happens to the reference of the object passed as a parameter? Nothing, it isn’t overwritten: it’s simply ignored inside the function, while the new obj created within will live only in that function’s scope and will be destroyed at the end of its execution.




Important note

A variable name is not an alias of a memory address. obj1 is not a shortcut for “0xA23b”: it’s just a label pointing to that address. When you create a new object, the label can easily point elsewhere. It’s not that we use the reference’s address instead of variable names: we are simply changing what happens in that memory cell.




How to avoid side effects?

As we’ve seen, objects in JS are mutable. This provides the flexibility that defines the language, but often at a cost too high for large applications. However, this can be mitigated. Over the years, several methods have been developed to make objects immutable:

But we’ll explore these in another article 🙂