Loading...
Loading...
How JavaScript tracks where it is in your code. One thing at a time.
Module 6 · How JavaScript Works
Understanding the engine makes you a better debugger. Execution contexts, the call stack, hoisting, memory allocation, closures, and the prototype chain explain why JavaScript behaves the way it does under the hood.
The call stack tracks which function is running now and which callers are waiting to resume. Push on every call, pop on every return — visualize recursion, nested calls, and stack overflow errors.
JavaScript looks simple on the surface, but the engine does a lot of work behind the scenes. Variables are hoisted, functions create new execution contexts, the call stack tracks nested calls, and the prototype chain resolves property lookups.
This module is for developers who want to stop guessing and start understanding. Visual diagrams of the call stack, heap, and scope chain make abstract concepts concrete — and directly improve your debugging skills in real projects.
When DevTools shows a stack trace or the engine throws 'Maximum call stack exceeded,' you are reading the call stack. It is the step-by-step story of how execution reached the current line — essential for every debugger.
A stack of function calls. Last in, first out (LIFO).
// The call stack tracks function execution: // • Function called → PUSH frame onto stack // • Function returns → POP frame off stack // • Stack empty → program is idle function third() { return "done"; } function second() { return third(); } function first() { return second(); } first();
Call Stack visualization:
← top of stack (currently executing)
Watch functions push and pop from the stack.
Program starts
first();
When the stack gets too deep, it crashes.
// Infinite recursion → stack overflow: function forever() { forever(); // calls itself with no end condition } forever(); // RangeError: Maximum call stack size exceeded // The stack fills up until the engine stops it: // forever() → forever() → forever() → forever() → ... // Stack size varies: ~10,000-25,000 frames (depends on engine)
⚠️ Stack overflow means your recursion has no base case, or it's too deep. Always ensure recursive functions have an exit condition that will be reached.
Functions that call themselves with a base case.
function factorial(n) { if (n <= 1) return 1; // base case! return n * factorial(n - 1); } factorial(4); // 24
Each call adds a frame to the stack. The base case (n <= 1) stops the recursion.
JavaScript has one call stack. One thing at a time.
// JS is single-threaded: // Only ONE function executes at a time. // If a function is slow, everything else waits. function slowTask() { // Blocks the thread for 3 seconds const end = Date.now() + 3000; while (Date.now() < end) {} // busy wait console.log("Done!"); } slowTask(); // UI freezes during this! console.log("After"); // waits 3 seconds
How async solves this:
When you use setTimeout, fetch, or addEventListener, the task is handed off to the browser/runtime. The call stack stays free. When the task completes, a callback is queued and executed when the stack is empty — this is the Event Loop.
Common questions about call stack.
Step through the code and watch variables change
1function first() {2 console.log("first start");3 second();4 console.log("first end");5}67function second() {8 console.log("second start");9 third();10 console.log("second end");11}1213function third() {14 console.log("third");15}1617first();
No output yetExecution begins — first() is called and pushed onto the stack.