How JavaScript Code is Executed:

I'm Yasheela, an undergraduate with a deep interest in DevOps, and cloud technologies. Currently working on exciting projects on all things DevOps. I’m passionate about simplifying complex concepts and sharing practical insights. Through my Hashnode blog, I document my learning journey, from building scalable applications to mastering cloud services, with the goal of empowering others to grow their tech skills. Let's Learn Together !!
Execution Context and the Call Stack Explained
If you've ever wondered how JavaScript runs line by line, what happens behind the scenes, or why terms like "execution context" and "call stack" keep popping up in technical interviews, you're in the right place. This post breaks down exactly how JavaScript executes your code, step by step, using clear examples and visual mental models. By the end, you'll understand how JavaScript manages variables, functions, and keeps track of what's running—even in complex, deeply-nested functions.
https://www.youtube.com/watch?v=iLWTnMzWtj4
What Happens When You Run a JavaScript Program?
When you run a JavaScript program, a lot more happens than meets the eye. Before anything else appears on your console, JavaScript gets busy behind the scenes, building the core environment where it will execute your code. This is known as the Execution Context.
Execution Context is the internal environment where JavaScript code runs. Think of it as a large box with two main compartments:
Memory Component (also known as the variable environment)
Code Component (or the thread of execution)
Every time you run JavaScript, an execution context is created—this is essential for any code to run.
The Two Key Phases of the Execution Context
When JavaScript creates an execution context, it processes it in two main phases:
Phase 1: Memory Creation Phase
Phase 2: Code Execution Phase
These two phases prepare and then run your code in order, ensuring JavaScript knows where everything lives in memory and how to execute each instruction.
Breaking Down Execution Context Using a Simple Example
Here's a practical JavaScript example to make things concrete:
var n = 2;
function square(num) {
var ans = num * num;
return ans;
}
var square2 = square(n);
var square4 = square(4);
Let's walk through how this code executes, step by step.
1. Creation of the Global Execution Context (GEC)
When the program starts, JavaScript creates the Global Execution Context (GEC). This acts as the default environment in which your entire script is first run.
The GEC consists of:
The Memory Component (where variables and functions live)
The Code Component (which runs the code step by step)
Phase 1: Memory Creation in the GEC
In the memory creation phase, JavaScript scans the code and allocates memory:
Variables like
n,square2,square4are set up and assigned a special value: undefined. This means memory space is reserved, but no real value is placed yet.Functions like
squarealso get memory allocated. However, the entire function code (all lines inside the function) is stored here, not just the name.
At this stage, nothing actually runs. JavaScript is simply setting the stage, placing undefined as a placeholder for variables, and copying function definitions into memory.
Why undefined?undefined acts as a placeholder. It means, "I've reserved space for this, but I haven't given it any value from the actual code yet." It's a unique, special keyword in JavaScript and deserves its own deep dive (which you'll find in a future post).
Phase 2: Code Execution in the GEC
Now, JavaScript starts executing code line by line:
The variable
nreceives the value2, replacing the undefined placeholder.The
squarefunction definition is recognized but nothing is executed at this point.When reaching
square2 = square(n), JavaScript realizes it needs to run thesquarefunction.The same happens for
square4 = square(4), but this time with a different argument.
Key points:
Functions are not executed when they're defined, only when they're called (invoked).
When a function is invoked, JavaScript creates a brand new Execution Context just for that function call.
Understanding Function Invocation and Its Execution Context
When a function is called—such as square(n) or square(4)—JavaScript needs to manage this temporary, local piece of work. The language does this by creating a new Execution Context for each function call.
What Happens When You Invoke a Function?
A function invocation is any time a function is called using parentheses, like square(n). This action signals JavaScript to execute that mini-program, separate from the rest of the global code.
Anatomy of a Function's Execution Context
Like the global one, each function call's execution context contains:
A Memory Component
A Code Component
And, just like before, these get processed in two distinct phases.
Detailed Step-by-Step: What Happens Inside square(n)?
Let's break down square(n) in detail:
Phase 1: Memory Creation Phase
Space is reserved for function parameters (here,
num) and any local variables (likeans).Both are initialized with undefined.
Quick definitions:
Parameter: The variable name in the function definition (
numinfunction square(num))Argument: The actual value passed during the function call (
n, which is 2 in the first call)
Phase 2: Code Execution Phase
The argument (
n, with value 2) is assigned to the parameter (num).JavaScript calculates
num * num, placing the result (2 * 2 = 4) inans.The function encounters the
returnstatement, sending the value ofans(4) back to where the function was called from.
What happens next?
The local execution context for
square(n)is destroyed. All the local workspace is cleared.The returned value (4) is placed in
square2, replacing the initial undefined.
Running square(4) Follows the Same Steps
Again, a new execution context is created for
square(4).numis assigned the value 4 this time.ansbecomes 4 * 4 = 16.The function returns 16, destroying its execution context.
square4now holds the value 16.
Visual Model: Think of Nesting Boxes
Imagine each function invocation as putting a new smaller box inside the previous one. Once a box (execution context) is finished, it's taken out and thrown away, and control moves back to the previous box.
Summary of steps inside a function invocation:
Allocate memory for parameters/local variables (
undefinedplaceholders)Assign argument values
Execute code line by line
Return result to caller
Delete local execution context
Summary of Execution Context Lifecycle in JavaScript
Let's review the core journey any JavaScript code takes:
The Global Execution Context is built first whenever a JavaScript program starts.
Every function call creates a new, nested Execution Context.
Each context always has a memory component (variables, parameters, functions) and code component (actual running code).
These contexts are handled in two separate phases: memory creation and code execution.
Memory is initialized with undefined as a placeholder before any real values are set.
After a function finishes (via a
return), its execution context is deleted, cleaning up all the local space.Control always returns back to the code that invoked the function.
Control flow in JavaScript relies on creating and destroying these contexts, ensuring only relevant code and variables are active at any moment.
How JavaScript Manages Execution Contexts: The Call Stack Explained
Picture yourself juggling several tasks—how do you keep track of which task to finish first? JavaScript uses a powerful tool for this: the Call Stack.
What Is the Call Stack?
The call stack is a stack data structure (think a pile of plates, where you can only add or remove the top plate) the JavaScript engine uses to manage execution contexts.
How the Call Stack Works
Here's how JavaScript uses the call stack step by step:
Global Execution Context is created and pushed at the bottom of the stack.
Each time a function is invoked, its Execution Context is created and pushed to the top of the stack.
When a function returns (finishes), its context is popped off the stack, and control goes back to whatever is in the stack below (usually the code that called that function).
This approach lets JavaScript handle deeply nested functions and even recursion smoothly.
Example Call Stack Flow (with square(n) and square(4))
At the start, the global context sits at the bottom.
square(n)is called: its context is pushed on top.When
square(n)returns, its context is popped off.Next,
square(4)is called: its context is pushed on top.After
square(4)returns, that context is popped too.At the end of the program, the global context is cleared, and the call stack becomes empty.
Call Stack Visual:
[Top of the Stack]
-------------------
Execution Context: square(4)
-------------------
Execution Context: square(n)
-------------------
Global Execution Context
[Bottom of the Stack]
As each function completes, its execution context is removed, and the stack shrinks.
Why the Call Stack Matters
The call stack keeps track of where to return after each function call, making it possible to handle deeply nested functions and recursion without confusion. It ensures JavaScript always knows what to run next.
Alternative Names for the Call Stack
If you see terms such as these, they all mean the call stack:
Execution Context Stack
Program Stack
Control Stack
Runtime Stack
Machine Stack
No matter the name, this structure keeps code execution organized and efficient.
Additional Notes and Next Steps
These concepts may feel a bit tricky at first, but reviewing them a couple of times helps them click. Keep exploring Execution Contexts—you'll keep seeing them in every complex JS project or job interview.