Understanding Call Stack and Heap Memory in JS

Jennifer Takagi
Level Up Coding
Published in
3 min readOct 3, 2020

--

Hi guys, I promised in my previous post: Hoisting in JavaScript that I would talk about the reason why we can’t change values into a const variable — and also why to push a value into an array or add new keys into an object is pretty possible.

Photo by Fredy Jacob on Unsplash

JavaScript abstracts a lot of things for us — for example, it reads and executes the code like magic , right? — but behind the scenes, JS has to store and write information and needs to keep track of what will happen line by line. To be able to do these things, JS engine has these little weapons: call stack and memory heap.

JavaScript’s memory model

First of all, you must understand what happens when we declare a variable and initialize it. In the following example, I declared a number1 variable with the value of 1. Right after this, I declared that the number2 was equaled to number1 and I also changed number1's value.
What do you think that will be printed to number2?

Example of JS’s memory model

If you answered that it would be 2, you’re wrong! :( Let’s check what happened behind the scenes:

1. When number1 was created, JS created a unique identifier to this and allocated an address in memory (eg. A001), it also stored the value at the allocated address.

2. Since I decided that number2 was equaled to number1, it means that number2 is equaled to that address memory: A001, and not equal to the number1’s value, this definition is very important!

3. When I changed the number1's value, JS allocated a new address in its memory, and stored the value 2 on A002 address, it happened because primitive data types (string, number, bigint, boolean, undefined, and symbol) in JS are immutable!

The call stack does what its name says: stacks the calls (of functions in our case) -. It’s here that the primitive data are stored. We can see this happening in the DevTools, when we run a simple script and set a breakpoint, we can see in the right sidebar the call stack of this code, it stacks all function’s calls, an interesting thing is that call stack is first in last out, so it adds the function’s call to the top, execute it and remove it after all code was run.

DevTool with a breakpoint to checks the call stack.

What about the memory heap? Oh, the memory heap is where the non-primitive are stored! The big difference between call stack and memory heap is that the heap can store unordered data that grows dynamically — like array and object.

Note about const and non-primitive data

At this point, you may notice that we can’t reassign values to a const variable because the const keyword doesn’t allow us to change — not the value — the memory address from a variable! But, why we can push elements on a const array or add new properties on an object?

As I wrote above, the memory heap has the responsibility to allocate the non-primitives data type’s value, so when we create a variable as an array, the JS creates a unique identifier, allocates an address memory on the call stack, and (here’s the magic) stores a value of a memory address on the heap:

Identifiers ---------------- Call Stack ---------------- Heap
Address -- Value Address -- Value
number1 --------- A003 -- 2
number2 --------- A001 -- 1
names --------- A004 -- B001 --------- B001 -- []

And when we push values into the names array, it will not change the address memory (!), instead, it will change the value on the heap — the same occurs with the object, it has the same behavior as we saw above.

That’s all folks, thanks for reading and I hope this post helps you to understand a little deeper about the JS magic :)

--

--

Developer focused on technology for troubleshooting! A clean code lover, functional programming enthusiast and passionate about sharing knowledge.