Skip to main content

Passing arguments by value or by reference

When we pass arguments into a function, JavaScript copies them, and how exactly it copies depends on the data type: primitives are copied by value, while objects, arrays and functions are passed by reference, or more precisely by a copy of the reference. That is why some changes made inside a function are visible outside and others disappear with the call.

Theory

TL;DR

  • Primitives (number, string, boolean, null, undefined, symbol, bigint) are passed by value: the parameter gets a full copy.
  • Objects, arrays and functions are passed by reference, that is, the parameter gets a copy of the reference to the same region of memory.
  • Changing the contents of an object inside a function (obj.name = "Bob", arr.push(4)) is visible in the original.
  • Reassigning the parameter (obj = {...}, arr = [...]) does not touch the original, because only the local copy of the reference changes.
  • Strictly speaking, JavaScript always passes by value: for objects that value is a reference.

Quick example

javascript
let a = 10; function changeValue(x) { x = 20; // we change the copy } changeValue(a); console.log(a); // 10

The value of a did not change, because only its copy was written into x.

Passing by value

Primitives, that is numbers, strings, booleans, null, undefined, symbol and bigint, are copied in full.

Data typeHow it is passed
Primitives (numbers, strings, booleans, null, undefined, symbol, bigint)by value
Objects, arrays, functionsby reference (more precisely, by a copy of the reference)

Explanation for the example above:

  • A copy of the value of a is written into x.
  • Changing x has no effect on a whatsoever.

In memory it looks like this:

text
a -> 10 x -> 10 (copy)

Passing by reference

Objects, arrays and functions are not copied whole. Instead, a reference to their address in memory is passed.

javascript
const user = { name: "Alice" }; function rename(obj) { obj.name = "Bob"; } rename(user); console.log(user.name); // "Bob"

Explanation:

  • The variable user holds a reference to the object in memory.
  • That same reference is copied into obj, so both variables point to one and the same object.
  • Changes made through obj are visible through user as well.

In memory it looks like this:

text
user --+ v { name: "Bob" } ^ obj ---+

Reassigning the reference inside a function

If you change the reference itself inside the function, the original stays untouched.

javascript
const user = { name: "Alice" }; function reassign(obj) { obj = { name: "Charlie" }; // a new reference } reassign(user); console.log(user.name); // "Alice"

What happens here:

  • The reference to user is first copied into obj.
  • Then obj is redirected to a new object, while the original reference (user) stays the same.

This is exactly the proof that a copy of the reference is passed, not the variable slot itself.

Array example

An array is an object too, so the same rules apply. Changing the contents is visible outside:

javascript
const numbers = [1, 2, 3]; function modify(arr) { arr.push(4); // we change the contents } modify(numbers); console.log(numbers); // [1, 2, 3, 4]

But reassigning the reference is not:

javascript
function modify(arr) { arr = [9, 9, 9]; // we create a new array } modify(numbers); console.log(numbers); // [1, 2, 3]

Summary and a simple analogy

Data typeHow it is passedDoes a change inside the function affect the original?
Primitives (number, string, boolean, null, undefined, symbol, bigint)By valueNo
Objects, arrays, functionsBy reference (a copy of the reference)Yes, if the contents change
Reassigning the parameter inside the functionA local copyNo

An analogy that works well in an interview:

  • By value is like handing over a photocopy of a sheet of paper: if you write something on your copy, the original does not change.
  • By reference is like handing over the address of a safe: both of you can open the same safe and change what is inside.

Common mistakes

  • Believing that JavaScript has true pass by reference. It does not: a function cannot reassign the variable it was given. The accurate wording is "passing a copy of the reference", also known as call by sharing.
  • Confusing mutation with reassignment. obj.name = "Bob" changes the shared object, obj = {...} changes only the local parameter.
  • Thinking that const protects against changes. const user = {...} forbids reassigning user, but it does not forbid changing its properties inside a function. For that you need Object.freeze or a copy.
  • Expecting a shallow copy to solve everything. { ...user } and structuredClone behave differently: the spread copies only the top level, so nested objects stay shared.
  • Forgetting that a string is immutable. A method such as str.toUpperCase() does not change the argument, it returns a new string that you have to assign.

Short Answer

Interview ready
Premium

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