Skip to main content

Command Palette

Search for a command to run...

By value vs By Reference in JavaScript

Updated
4 min read
By value vs By Reference in JavaScript
T

Just a guy who loves to write code and watch anime.

In JavaScript, parameters are passed by value or by reference.

To understand the difference, let's understand how things are stored in memory on both the stack and the heap.

Recap of Stack

  • Purpose: Fast access, temporary storage

  • Contains:

    1. Primitive values directly

    2. References/addresses to heap objects

    3. Function call information (stack frames)

  • Characteristics:

    • Fixed size (smaller)

    • LIFO (Last In, First Out)

    • Automatic memory management

    • Each function call creates a new frame

    • Very fast access

// Stack Example
function doStuff() {
  let x = 42; // Goes on stack
  let y = true; // Goes on stack
  let objRef = 0x123; // Address goes on stack
}

It gets way into the weeds of how programming languages work, but to keep track of the data on the stack, you have a stack and frame pointer. Stack pointer points to the top of the stack. Frame pointer points to the current function call. Anyways, that's out of scope for this post.

The main thing you should know is that the object lives in the heap. The addresses is what we refer to when writing code.

Recap of Heap

  • Purpose: Dynamic storage, flexible memory

  • Contains:

    1. Actual objects

    2. Arrays

    3. Any data with dynamic size

  • Characteristics:

    • Dynamic size (larger)

    • No particular order

    • Managed by garbage collector

    • Can grow/shrink as needed

    • Slower than stack

// Heap Example
let obj = {
  // Lives in heap at some address (e.g., 0x123)
  name: "example",
  data: [1, 2, 3],
  nested: { x: 1 },
};

To access the object, we'd use the reference 0x123 from the stack.

Key differences between Stack and Heap

  • Stack: Fast, fixed-size, automatic cleanup

  • Heap: Flexible, dynamic-size, garbage collected

Dereferencing

Again, I don't wanna get way into the details, but you might be familiar with the term "dereferencing".

Maybe you've heard of it from university or from a book.

It simply means that you're looking up the actual value from the reference.

Let me show you some C code:

int main() {
  int x = 42;
  int* ptr = &x; // This is a pointer to the address of x
  printf("%d\n", *ptr); // Here we're dereferencing the pointer, which means we're looking up the actual value of x's address to get the x value which is 42
  return 0;
}

Pass by Value vs Pass by Reference

With that out of the way, let's talk about what matters for JavaScript.

Let me show you some JavaScript code:

const obj = { count: 0 };

function doStuffWithObject(obj) {
  obj.count = 1;
}

doStuffWithObject(obj);

console.log(obj); // { count: 1 }

Let's look at another piece of code with a primitive value:

const count = 0;

function doStuffWithPrimitive(count) {
  count = 1;
}

doStuffWithPrimitive(count);

console.log(count); // 0

The first example is what we call "pass by reference". The second example is what we call "pass by value".

Inside the function, we're actually doing a copy of the parameter.

In the case of the object, we're copying the reference, meaning the address, which points to the same object in the heap.

In the case of the primitive value, we're copying the value, which is not the same in memory, because the ACTUAL value is copied here.

const obj = { count: 0 }; // address -> 0x123

function doStuffWithObject(obj) {
  // Inside here we copy `obj`
  // But we're copying the address!!
  // So we're copying the address -> 0x123

  // Here under the hood we're dereferencing the address
  // And then we're modifying the value of the object
  // That is WHY the original object is modified
  obj.count = 1;
}

Fun fact

let obj1 = { value: 1 };
let obj2 = { value: 1 };
let sameAsObj1 = obj1;

obj1 !== obj2; // true (different objects in memory)
obj1 !== sameAsObj1; // false (same object in memory)

You may have see that when working with JS {} === {} is false. That's true because the brackets create new objects in memory.

But if you look at the code example above, obj1 and sameAsObj1 are the same object in memory, so when comparing them, they end up being true.

Summary

I may have been a bit fast since I'm writing for myself and this is from my notes.

But if you wanna dig deeper into how all of this works, I recommend playing around with code and reading up on the topic.

If you wanna learn programming language stuff, I recommend learning C and how things work under the hood.

If you've dabbled in some C, it shouldn't be too overwhelming for you to read this: Memory, Pointers and C under the hood. (full guide)