Before understanding async behavior, closures, or scope, you must fully grasp execution context. It is the foundation of how JavaScript actually runs code internally. An execution context is the environment where a piece of JavaScript code is executed.
Understanding execution context explains how variables, functions, and the this keyword behave for any specific block of code. Every time JavaScript runs something, like a script or a function, it creates a new execution context.
Three Types of Execution Context
| Type | Description |
|---|---|
| Global Execution Context | Created once per program, represents the global scope |
| Function Execution Context | Created for each function call |
| Eval Execution Context | Created when using eval() (rarely used, not recommended) |
Global Execution Context
When you open a JavaScript file or run a script, the engine automatically creates the global execution context.
It creates the global object (window in browser, global in Node.js), creates a special this binding that points to the global object, and sets up memory for global variables and functions.
var name = "John";
function greet() {
console.log("Hello " + name);
}
Here, the global execution context is created. Memory is allocated for name and greet. Then the code is executed line by line.
Function Execution Context
Every time a function is called, a new execution context is created for that function only.
Each function execution context has its own variable environment (local variables and parameters), lexical environment (scope chain and outer references), and this binding.
var name = "John";
function greet() {
var message = "Hello " + name;
console.log(message);
}
greet();
Flow
- Global Execution Context created for the entire file
- When greet() is called, a new Function Execution Context is created
- Inside it, a local variable message and parameter space are created
- After completion, this context is popped off the call stack
Structure of an Execution Context
Each Execution Context has two main phases and three key components.
Phases
- Creation Phase (Memory allocation)
- Execution Phase (Code runs line by line)
Components
| Component | Description |
|---|---|
| Variable Environment | Stores variables and function declarations |
| Lexical Environment | Stores identifiers and references to outer scopes |
| this Binding | Determines the value of this in the context |
Creation Phase
Before executing code, the JavaScript engine scans it and allocates memory.
During this phase, variables are initialized to undefined, functions are stored entirely in memory, and the this keyword is bound.
console.log(a);
var a = 5;
function test() {}
Creation Phase:
a: undefined
test: function reference
this: global object (window/global)
Execution Phase:
a = 5
This is why var is hoisted but initialized to undefined.
Execution Phase
Now the code executes line-by-line. Variable assignments happen. Functions are invoked, creating new execution contexts. The call stack grows and shrinks dynamically.
Call Stack (Execution Context Stack)
All execution contexts are managed using the call stack, also known as the execution stack.
Behavior
- When the JavaScript engine starts, the Global Execution Context is pushed onto the stack
- When a function is invoked, a new Function Execution Context is pushed on top
- When a function returns, the Function Execution Context is popped off
function one() {
console.log("One");
two();
}
function two() {
console.log("Two");
}
one();
Stack flow:
1. GEC created → pushed
2. one() called → FEC(one) pushed
3. two() called → FEC(two) pushed
4. two() completes → popped
5. one() completes → popped
6. stack empty → program ends
Inside a Function Execution Context
Let’s look at what’s inside a typical function execution context:
function add(x, y) {
let sum = x + y;
return sum;
}
add(2, 3);
Function Execution Context:
{
Variable Environment: {
x: 2,
y: 3,
sum: undefined
},
Lexical Environment: {
outer: Global Environment
},
this: undefined (or global object in non-strict mode)
}
Lexical Environment
A Lexical Environment is where variable identifiers and references are stored. It also contains a reference to its outer (parent) environment, forming the scope chain.
Structure
Lexical Environment = {
Environment Record: { local variables },
Outer Environment Reference: pointer to parent Lexical Environment
}
When the JavaScript engine defines a function, it stores the outer environment reference of where that function was created. When executed, that reference allows the function to walk up the scope chain to find variables.
Example
let a = 10;
function outer() {
let b = 20;
function inner() {
let c = 30;
console.log(a + b + c);
}
inner();
}
outer();
Lexical Chain:
inner() → outer() → global
When inner() runs, it first looks for a, b, c in its own environment. If not found, it looks outward (lexically), not at runtime order.
This is what enables closures. Inner functions remember their outer variables even after the outer function finishes.
this Binding in Execution Context
| Context | Value of this |
|---|---|
| Global Context | Global object (window in browser, global in Node) |
| Function Context (non-strict) | Global object |
| Function Context (strict mode) | undefined |
| Inside an Object Method | That object |
| Inside a Class Constructor | The instance being created |
function show() {
console.log(this);
}
show(); // → window (in browser)
Strict mode:
"use strict";
function show() {
console.log(this);
}
show(); // → undefined
Visualization
┌───────────────────────────┐
│ Call Stack │
│ ┌───────────────────────┐ │
│ │ Function Context (FEC)│ │
│ └───────────────────────┘ │
│ ┌───────────────────────┐ │
│ │ Global Context (GEC) │ │
│ └───────────────────────┘ │
└───────────────────────────┘
Each Context has:
- Variable Environment
- Lexical Environment
- this Binding
Summary
| Type | Created When | Contains | Scope Reference |
|---|---|---|---|
| Global EC | JS starts | Global vars and functions | None (top-level) |
| Function EC | Function called | Parameters, local vars | Outer environment |
| Eval EC | eval() called | Temporary eval vars | Parent scope |
| Each Context | Always | Variable Env, Lexical Env, this | Yes |
An execution context is the box where your code runs. The global context is the base box for the entire program. A function context is a new box created per function call. The lexical environment contains variables and a link to the outer box. The call stack is a stack of these boxes, and JavaScript runs top to bottom. The this keyword is the object that owns the current execution.
Understanding execution context is essential for grasping closures, scope chains, and how JavaScript manages memory and execution order.