Does JavaScript Pass by Reference or Value?

Mateen KianiMateen Kiani
5 min read

Does JavaScript Pass by Reference or Value?

Introduction

JavaScript is at the heart of modern web development, powering dynamic pages and interactive features. Yet developers often stumble on one fundamental question: how does JavaScript pass data between variables and functions? It’s easy to assume everything shares the same behavior, but there’s a hidden nuance in how primitives and objects get handled behind the scenes. So, does JavaScript pass by reference or value when you assign or pass variables?

JavaScript actually uses both strategies. Primitive types—like numbers, strings, and booleans—are passed by value, creating independent copies. Objects, arrays, and functions, on the other hand, are passed by value of the reference, which feels like pass-by-reference. Understanding this split helps you write safer code, avoid subtle bugs, and optimize performance.

Primitive Types and Value Passing

In JavaScript, the primitive types are:

  • Number
  • String
  • Boolean
  • undefined
  • null
  • Symbol
  • BigInt

When you assign a primitive value, JavaScript copies the value into the new variable. That means changes to one variable don’t affect the other.

let a = 10;
let b = a;  // b gets its own copy: 10
b = 20;
console.log(a); // 10
console.log(b); // 20

Here, a remains 10 even after updating b. This behavior is predictable. You can pass primitives into functions without worrying about side effects:

function increment(x) {
  x++;
  return x;
}

let num = 5;
let newNum = increment(num);
console.log(num);    // 5
console.log(newNum); // 6

Because x is a copy, the original num stays the same. This isolation reduces unexpected interactions and makes primitive operations straightforward.

Tip: Use primitives when you need immutable, independent values. This avoids accidental shared state.

Objects and Reference Values

Objects are more complex. When you assign or pass an object, JavaScript copies the reference value, not the actual object. Both variables then point to the same underlying structure.

let obj1 = { name: 'Alice' };
let obj2 = obj1;
obj2.name = 'Bob';
console.log(obj1.name); // 'Bob'

Here, obj1 and obj2 share the same object. Changing a property via one variable affects the other. This is why some call it “pass by reference,” but technically it’s pass by value of the reference.

Under the hood, each object lives in the heap. Variables hold a pointer (address) to that location. When you copy the pointer, both variables refer to the same heap object.

Why This Matters

  • Shared Mutations: Two parts of your code can unknowingly change the same object.
  • Memory Use: References are lightweight copies of pointers, not full objects.

Understanding this helps you decide when to clone objects or design immutable patterns.

Arrays and Functions as References

Arrays and functions follow the same rule as objects. They live in the heap, so variable assignments copy the pointer, not the data.

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

function greet() {
  console.log('Hello');
}
let sayHi = greet;
sayHi();  // 'Hello'

In the array example, modifying arr2 also modifies arr1. For functions, copying the reference allows you to pass or store functions easily.

Note: You can use methods like slice, concat, or spread ([...]) to create shallow copies of arrays and avoid shared mutations.

Copying Data: Shallow vs. Deep

Often you need a fresh copy of an object or array. Two approaches exist:

  1. Shallow Copy – duplicates top-level properties but keeps nested references.
  2. Deep Copy – recursively clones all nested data.

Shallow Copy Techniques

  • Object.assign
  • Spread syntax: { ...obj } or [ ...arr ]
let original = { a: 1, nested: { b: 2 } };
let copy = { ...original };
copy.nested.b = 99;
console.log(original.nested.b); // 99 (shared nested object)

Deep Copy Techniques

  • JSON methods (simple objects only):
    let deep = JSON.parse(JSON.stringify(original));
    
  • StructuredClone (modern browsers and Node.js):
    let deep2 = structuredClone(original);
    

Caution: JSON approach drops functions, undefined, and symbols. Use libraries like Lodash’s cloneDeep for robust deep cloning.

Common Pitfalls and Best Practices

Knowing pass-by behavior prevents bugs. Here are tips:

  • Avoid unintended mutations: Don’t directly change function parameters that are objects.
  • Use const for references: Prevent reassigning references when you mean to keep them stable.
  • Prefer immutability: Embrace patterns that return new objects instead of tweaking old ones.
  • Document shared data: Mark which functions may alter object properties.
  • Leverage tools: Linters can warn on reassignments or mutations.
// Bad practice
function updateUser(user) {
  user.isAdmin = true;  // mutates original
}

// Better practice
function promoteUser(user) {
  return { ...user, isAdmin: true };
}

Following these patterns leads to safer and more maintainable code.

Conclusion

In JavaScript, primitives are passed by value, giving you independent copies and fewer side effects. Objects, arrays, and functions are passed by the value of their reference, which can feel like pass-by-reference. Recognizing this split is key to writing bug-free code.

Whenever you work with objects or arrays, ask yourself:

  • Do I want shared mutations? If not, create a copy.
  • Should I use shallow or deep cloning?

By applying clear cloning strategies and embracing immutability, you’ll avoid common pitfalls and make your code more predictable. Now you can confidently decide when to share a reference and when to isolate data.

"Understanding how JavaScript passes data is like having a map in unfamiliar territory—it guides you to safer, more efficient code."

Internal Resource: Learn more about JavaScript objects in this developers guide on JavaScript objects.

0
Subscribe to my newsletter

Read articles from Mateen Kiani directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Mateen Kiani
Mateen Kiani