Skip to main content

Pass by value vs pass by reference

"By value" means the variable stores the value itself, so copying creates a new independent copy of the data; "by reference" means the variable stores only a pointer to a place in memory, and it is that pointer that gets copied. In JavaScript primitives behave by value, while objects and every complex data structure behave by reference.

Theory

TL;DR

  • Primitives (number, string, boolean, null, undefined, symbol, bigint) are passed by value.
  • Objects (object, array, function, Date, Map, Set and so on) are passed by reference.
  • A copy of a primitive is fully independent: changing b does not affect a.
  • A copy of an object is the same structure in memory: a change made through one variable is visible through the other.
  • To get an independent object you need a shallow ({ ...obj }) or a deep copy.

Quick example

javascript
// by value let a = 5; let b = a; // the value 5 is copied b = 10; console.log(a); // 5, unchanged console.log(b); // 10 // by reference const user1 = { name: 'Maria' }; const user2 = user1; // the REFERENCE is copied, not the object itself user2.name = 'Alex'; console.log(user1.name); // "Alex" console.log(user2.name); // "Alex"

What "by value" means

The variable stores the value itself, not a reference to it. Copying creates a new independent copy of the data.

Primitives (simple data types) are passed by value. They are:

  • number
  • string
  • boolean
  • null
  • undefined
  • symbol
  • bigint
javascript
let a = 5; let b = a; // the value 5 is copied b = 10; console.log(a); // 5 <- unchanged console.log(b); // 10

a and b are now two independent values, and changing b does not affect a.

What "by reference" means

The variable does not store the object itself, it stores a reference (a pointer) to the place in memory where the object lives.

All objects and complex data structures are passed by reference:

  • object
  • array
  • function
  • Date, Map, Set and so on
javascript
const user1 = { name: 'Maria' }; const user2 = user1; // the REFERENCE is copied, not the object itself user2.name = 'Alex'; console.log(user1.name); // "Alex" console.log(user2.name); // "Alex"

Both variables point at one and the same object in memory, so changing user2 also changes user1.

Visually:

text
+------------+ | user1 | --+ +------------+ | v { name: "Maria" } ^ +------------+ | | user2 | --+ +------------+

Example with an array

An array is an object too, so the same rule applies:

javascript
const arr1 = [1, 2, 3]; const arr2 = arr1; arr2.push(4); console.log(arr1); // [1, 2, 3, 4] console.log(arr2); // [1, 2, 3, 4]

Both arrays are one and the same object in memory.

How to copy an object without carrying the reference

If you want a new independent object, you have to copy the data explicitly.

A shallow copy (spread):

javascript
const user1 = { name: 'Tim', age: 25 }; const user2 = { ...user1 }; // the spread operator user2.name = 'Alex'; console.log(user1.name); // "Tim" console.log(user2.name); // "Alex"

A deep copy (for nested objects):

javascript
const user1 = { name: 'Tim', address: { city: 'Kyiv' } }; const user2 = JSON.parse(JSON.stringify(user1)); // deep cloning user2.address.city = 'Lviv'; console.log(user1.address.city); // "Kyiv" console.log(user2.address.city); // "Lviv"

Stack, heap and the summary tables

TypeWhere it is storedWhat happens on copy
Primitive (by value)on the stacka new copy is created
Object (by reference)on the heapthe reference to the same place is copied
Data typeHow it is passedExample
---------
string, number, boolean, null, undefined, symbol, bigintby valuelet a = 5; let b = a;
object, array, function, Date, Map, Setby referencelet obj2 = obj1;

In short:

  • By value creates a copy of the data.
  • By reference copies the pointer to the same object.
  • That is why changing one object affects the other whenever they are linked by a reference.

Common mistakes

  • Believing that const protects the contents of an object. const forbids reassigning the variable, but it does not forbid changing the fields of the object it points at.
  • Writing const copy = original for an object and thinking it is a copy. It is a second name for the very same object.
  • Confusing a shallow copy with a deep one: { ...user } copies only the top level, nested objects stay shared.
  • Reaching for JSON.parse(JSON.stringify(obj)) blindly: it drops undefined, functions and Symbol, turns a Date into a string and throws on circular references. For complex cases prefer structuredClone(obj).
  • Comparing objects with === and expecting true: { a: 1 } === { a: 1 } is false, because those are two different references.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.