An execution context is an environment created by the JavaScript engine that handles the transformation and execution of JavaScript code. Since browsers cannot natively understand high-level JavaScript code, it must be converted to machine code for execution.
When a JavaScript file is loaded, the Global Execution Context is created. This is the foundation where all JavaScript code execution begins.
const firstName = "john";
let lastName = "doe";
function greet(nameToGreet) {
const fullName = nameToGreet + " " + lastName;
return "Hello, " + fullName;
}
greet(firstName); // Function call creates new execution context- Default context when JavaScript engine receives a script file
- JavaScript code not inside any function gets executed here
- Only one GEC can exist per JavaScript file
- Created automatically when script loads
- Created whenever a function is called
- Separate context within the Global Execution Context
- Evaluates and executes code within that specific function
- Multiple FECs can exist (one per function call)
Every execution context goes through two main phases:
The execution context is associated with an Execution Context Object (ECO) that stores important data used during runtime. This phase has three stages:
A container that stores variable and function declarations within the execution context.
// During creation phase, memory allocation happens:
var x = 10; // x → undefined (hoisted)
let y = 20; // y → uninitialized (TDZ)
const z = 30; // z → uninitialized (TDZ)
function myFunc() {
// myFunc → function reference
return "Hello";
}Hoisting Process:
vardeclarations: Stored asundefined- Function declarations: Stored with complete function reference
let/const: Hoisted but remain uninitialized (see Variables, Scope, and Hoisting)
Scope defines how accessible code is to other parts of the codebase. The scope chain determines variable access through nested functions.
let globalVar = "I'm global";
function outer() {
let outerVar = "I'm outer";
function inner() {
let innerVar = "I'm inner";
// Scope chain: inner → outer → global
console.log(innerVar); // ✅ Found in inner scope
console.log(outerVar); // ✅ Found in outer scope
console.log(globalVar); // ✅ Found in global scope
}
inner();
}Lexical Scoping: Inner functions have access to outer function variables, but outer functions cannot access inner variables. This enables closures.
The this keyword refers to the context where an execution context belongs.
// Global context
console.log(this); // Window object (in browsers)
// Object method context
const user = {
name: "John",
greet() {
console.log(this.name); // "John" - `this` refers to user object
},
};
// Function context
function regularFunction() {
console.log(this); // Window object (non-strict mode)
}Actual code execution begins. The Variable Object reads the code and updates variables with their actual values.
// Creation Phase: x = undefined, myFunc = function reference
// Execution Phase: x = 10, then function executes
var x = 10; // x gets actual value: 10
console.log(x); // Outputs: 10
function myFunc() {
return "Hello World";
}
const result = myFunc(); // Function executes, returns "Hello World"The Call Stack keeps track of execution contexts created during script execution. JavaScript is single-threaded, so it can only execute one task at a time.
function firstFunction() {
console.log("First function start");
secondFunction();
console.log("First function end");
}
function secondFunction() {
console.log("Second function start");
thirdFunction();
console.log("Second function end");
}
function thirdFunction() {
console.log("Third function executed");
}
firstFunction();Call Stack Execution Order:
- Global Execution Context pushed to stack
firstFunction()called → FEC created and pushed to topsecondFunction()called → FEC created and pushed to topthirdFunction()called → FEC created and pushed to topthirdFunction()completes → popped from stacksecondFunction()completes → popped from stackfirstFunction()completes → popped from stack- Global context remains
| |
| thirdFunction() | ← Active (top of stack)
| secondFunction() |
| firstFunction() |
| Global Context |
|____________________|
var globalVar = "Global";
function outerFunction(param) {
var outerVar = "Outer";
function innerFunction() {
var innerVar = "Inner";
console.log(globalVar + " " + outerVar + " " + innerVar + " " + param);
}
innerFunction();
}
outerFunction("Parameter");Execution Steps:
-
Global EC Created
- Creation:
globalVar = undefined,outerFunction = function reference - Execution:
globalVar = "Global"
- Creation:
-
outerFunction EC Created (when called)
- Creation:
outerVar = undefined,innerFunction = function reference,param = "Parameter" - Execution:
outerVar = "Outer"
- Creation:
-
innerFunction EC Created (when called)
- Creation:
innerVar = undefined - Execution:
innerVar = "Inner", access scope chain for other variables - Output: "Global Outer Inner Parameter"
- Creation:
-
Stack Cleanup: innerFunction → outerFunction → Global Context
- Two Types: Global Execution Context and Function Execution Context
- Two Phases: Creation (memory allocation) and Execution (code running)
- Hoisting: Variables and functions are allocated memory before execution
- Scope Chain: Determines variable accessibility through nested scopes
- Call Stack: Manages execution order in LIFO (Last In, First Out) manner
- Single-threaded: JavaScript executes one thing at a time
thisBinding: Determined during execution context creation
- Variables, Scope, and Hoisting: Detailed explanation of hoisting and scope
- Functions: How function calls create execution contexts
- Closures: Enabled by lexical scoping and execution context preservation
Reference: Execution Context - FreeCodeCamp