JavaScript Execution Context
Before JavaScript runs any code, it sets up an environment to manage variables, functions, and the value of this.
That environment is called the execution context.
- What Is an Execution Context
- Types of Execution Context
- The Two Phases
- The Call Stack
- Connection to Hoisting, Scope, and Closures
What Is an Execution Context
Every time JavaScript runs a piece of code, it creates an execution context.
Each execution context manages three things:
- The variables and function declarations in the current scope
- The value of
this - A reference to the outer scope
Execution context is the underlying mechanism that makes hoisting, scope chains, this, and closures work.
Types of Execution Context
There are two main types:
Global Execution Context
Created when the program first starts. There's only one, and it manages all code that isn't inside a function.
In a browser, the global execution context's this points to window.
Function Execution Context
Created every time a function is called. Each call gets its own separate execution context — even if the same function is called multiple times.
function greet(name) {
const message = "Hello, " + name;
console.log(message);
}
greet("Charmy"); // creates one execution context
greet("Charmying"); // creates anotherThe Two Phases
Every execution context goes through two phases:
1. Creation Phase
Before any code runs, JavaScript:
- Scans all variable and function declarations
- Initializes
varvariables toundefined - Places
letandconstvariables in the TDZ (Temporal Dead Zone) - Fully hoists function declarations
- Determines the value of
this - Stores a reference to the outer scope
This is where hoisting happens.
2. Execution Phase
Code runs top to bottom:
- Variables get assigned their values
- Functions get called
console.log(a); // undefined — initialized during creation phase
console.log(b); // ReferenceError — in TDZ during creation phase
var a = 1;
let b = 2;The Call Stack
JavaScript is single-threaded — it can only run one execution context at a time.
The call stack keeps track of which execution contexts are active and in what order.
Here's how it works:
- The program starts — the global execution context is pushed onto the stack
- A function is called — a new execution context is pushed on top
- The function finishes — its execution context is popped off
- Execution resumes in the previous context
function first() {
console.log("first");
second();
}
function second() {
console.log("second");
}
first();Step by step:
If a function keeps calling itself recursively without stopping, the stack grows until it hits the limit and throws: RangeError: Maximum call stack size exceeded.
Connection to Hoisting, Scope, and Closures
Execution context is the foundation that ties several JavaScript concepts together.
Hoisting
Hoisting happens during the creation phase. By the time your code starts running, all variable and function declarations have already been processed.
Scope Chain
Every execution context holds a reference to its outer scope. Those references chain together, and JavaScript walks up the chain when looking up a variable.
Closures
When a function is defined, it captures a reference to the current execution context's scope. Even after that execution context is gone, the closure still holds onto it.
this
The value of this is determined during the creation phase, based on how the function was called.
Conclusion
The execution context is how JavaScript sets up and manages the environment for running code:
- The global execution context is created when the program starts
- A new function execution context is created on every function call
- The creation phase handles hoisting; the execution phase runs the code
- The call stack tracks which execution contexts are active
Understanding execution context gives you a clearer mental model for how hoisting, scope chains, closures, and this all fit together.