A JavaScript execution context is the environment in which JavaScript code is evaluated and executed. It determines how variables, functions, and other values are accessed while a program runs.
Whenever JavaScript code executes, the JavaScript engine creates an execution context to manage the code’s execution. Understanding execution context helps you learn how JavaScript handles variables, function calls, scope, and the call stack.
In this tutorial, you will learn about the global execution context, function execution context, and the lifecycle of an execution context.
What Is an Execution Context in JavaScript?
An execution context is an internal environment created by the JavaScript engine to execute code. It keeps track of variables, functions, scope information, and the current state of execution.
JavaScript mainly uses two types of execution contexts:
- Global Execution Context: Created to execute code outside functions.
- Function Execution Context: Created whenever a function is called.
For example:
let name = "Karim";
function greet() {
let message = "Hello";
console.log(message);
}
greet();
Output:
Hello
In this example, JavaScript creates a global execution context to handle the top-level code. When greet() is called, JavaScript creates a separate function execution context to execute the function body.
The global context and function context have their own environments for managing variables and execution.
Global Execution Context in JavaScript
The global execution context is the default execution context created when a JavaScript program begins running.
It handles code that is not inside a function. JavaScript creates the global execution context before executing the program’s top-level statements.
Consider this example:
let name = "Karim";
let age = 25;
console.log(name);
console.log(age);
Output:
Karim
25
JavaScript executes this code in the global execution context because both variables and the console.log() statements are at the top level.
How the Global Execution Context Works
The global execution context is commonly explained through two phases.
Creation phase
During this phase, the JavaScript engine prepares the environment for executing the code. It establishes bindings for declarations and initializes them according to the declaration type.
For example:
console.log(name);
var name = "Karim";
Output:
undefined
The var declaration is initialized with undefined during the creation phase. The assignment to "Karim" happens later during execution.
With let and const, the bindings are created but remain uninitialized until their declarations are evaluated. Accessing them before initialization causes a ReferenceError.
Execution phase
During this phase, JavaScript executes statements in order and performs assignments.
let name = "Karim";
name = "Ahmed";
console.log(name);
Output:
Ahmed
JavaScript first initializes name with "Karim". It then updates the value to "Ahmed" and prints the updated value.
Global Execution Context and the Global Object
In browser environments, the global object is generally window. In Node.js, it is globalThis, which provides a standard way to access the global object across JavaScript environments.
However, top-level declarations do not all behave the same way. In a classic browser script, a top-level var declaration generally creates a property on window, while top-level let and const declarations do not.
For example, in a classic browser script:
var city = "Hyderabad";
let country = "India";
console.log(window.city);
console.log(window.country);
Typical browser output:
Hyderabad
undefined
This example assumes the code runs as a classic browser script, not an ES module or a Node.js program.
Function Execution Context in JavaScript
A function execution context is created whenever a function is called. It provides an environment for executing that function’s code.
Each function call gets its own execution context, including its own local variables and parameters.
For example:
function greet(name) {
let message = "Hello, " + name;
console.log(message);
}
greet("Karim");
greet("Ahmed");
Output:
Hello, Karim
Hello, Ahmed
When greet("Karim") is called, JavaScript creates a function execution context with name set to "Karim". When greet("Ahmed") is called, JavaScript creates another function execution context with name set to "Ahmed".
The local variables and parameter values belong to their respective function calls.
How Function Execution Context Works
Consider the following example:
let number = 10;
function calculate() {
let number = 20;
console.log(number);
}
calculate();
console.log(number);
Output:
20
10
Here is what happens:
- The global execution context creates the global binding for
number, initialized to10. - JavaScript calls
calculate()and creates a function execution context. - Inside the function, the local
numberis initialized to20. - The first
console.log()prints the local value,20. - After the function finishes, its execution context is removed from the call stack.
- The final
console.log()prints the global value,10.
The local variable does not overwrite the global variable because they belong to different scopes.
To understand this behavior better, learn about JavaScript scope and variable access.
Global Execution Context vs Function Execution Context
The global and function execution contexts both help JavaScript execute code, but they serve different purposes.
| Feature | Global Execution Context | Function Execution Context |
|---|---|---|
| Creation | Created when program execution begins | Created whenever a function is called |
| Code handled | Top-level code | Code inside a function call |
| Variables | Manages global-scope bindings | Manages local bindings and parameters |
| Number created | Generally one per script or module execution | A new one for each function call |
| Lifetime | Usually lasts throughout the script’s execution | Usually lasts until the function returns, unless execution is suspended |
| Call stack | Initial context for execution | Added to the call stack when the function is called |
Function execution contexts can also access variables from outer scopes through JavaScript’s lexical environment and scope chain.
Execution Context Lifecycle in JavaScript
The execution context lifecycle describes the stages an execution context goes through while JavaScript prepares and executes code.
The lifecycle is commonly explained using three main stages:
- Creation phase
- Execution phase
- Completion and cleanup
Creation Phase
During the creation phase, JavaScript prepares the execution environment before executing the statements in that context.
This preparation includes establishing the necessary bindings for variables, functions, and other declarations. The precise initialization behavior depends on the declaration type.
For example:
console.log(value);
var value = 100;
Output:
undefined
The var binding is initialized to undefined before the assignment executes.
Function declarations are also generally available before their position in the source code:
sayHello();
function sayHello() {
console.log("Hello, JavaScript!");
}
Output:
Hello, JavaScript!
This behavior is commonly called hoisting. You can learn more in the JavaScript hoisting tutorial.
Execution Phase
After the environment is prepared, JavaScript executes the statements in the current context.
Consider this example:
let price = 500;
let quantity = 2;
let total = price * quantity;
console.log(total);
Output:
1000
JavaScript initializes price and quantity, calculates their product, stores the result in total, and prints 1000.
For a function call, the function’s statements execute in its own execution context.
function add(a, b) {
let result = a + b;
return result;
}
let answer = add(10, 20);
console.log(answer);
Output:
30
When add(10, 20) is called, JavaScript creates a function execution context, binds a to 10 and b to 20, calculates the result, and returns 30.
Completion and Cleanup
When a function finishes executing, its execution context is normally removed from the call stack. JavaScript then continues executing the code in the previous context.
For example:
function greet() {
console.log("Inside function");
}
console.log("Before function");
greet();
console.log("After function");
Output:
Before function
Inside function
After function
The function execution context is created when greet() is called. After the function returns, JavaScript continues in the surrounding execution context.
Removing an execution context from the call stack does not necessarily mean all related data is immediately destroyed. If a closure still references variables from that function, JavaScript can keep the necessary lexical environment alive.
How Execution Context Uses the Call Stack
JavaScript uses a call stack to keep track of active execution contexts. The call stack follows the Last In, First Out (LIFO) principle, meaning the most recently added context is the first one to be removed.
Consider this example:
function first() {
console.log("First function");
second();
}
function second() {
console.log("Second function");
}
first();
Output:
First function
Second function
The execution happens in this order:
- JavaScript begins with the global execution context.
- The call to
first()creates a function execution context. - Inside
first(), the call tosecond()creates another function execution context. second()finishes and its context is removed from the call stack.first()finishes and its context is removed.- JavaScript continues in the global execution context.
The call stack helps JavaScript keep track of which function is currently executing and where to resume execution when a function returns.
Execution Context Example in JavaScript
The following example combines the global execution context, function execution context, and call stack.
let number = 5;
function multiply(value) {
let result = value * 2;
return result;
}
let answer = multiply(number);
console.log(answer);
Output:
10
Here is how JavaScript executes the program:
- The global execution context is created.
- The global binding
numberis initialized to5. - JavaScript reaches the call to
multiply(number). - A function execution context is created, with
valueset to5. - The local variable
resultis initialized to10. - The function returns
10, and its execution context leaves the call stack. - The global binding
answeris initialized to the returned value. - JavaScript prints
10.
This example demonstrates how execution contexts organize the execution of a JavaScript program.
Frequently Asked Questions
What is an execution context in JavaScript?
An execution context is the environment in which JavaScript evaluates and executes code. It manages declarations, variable access, scope information, and execution state.
What are the main types of execution contexts?
The two main types commonly introduced to beginners are the global execution context and the function execution context. JavaScript also uses module execution contexts for ES modules.
When is the global execution context created?
The global execution context is established when JavaScript begins evaluating a script or other top-level code unit.
When is a function execution context created?
A function execution context is created when a function is called. Each function call has its own execution state and local bindings.
What are the stages of an execution context lifecycle?
The lifecycle is commonly explained as the creation phase, execution phase, and completion or cleanup. The exact internal processing depends on the JavaScript environment and type of code being executed.
What is the relationship between execution context and call stack?
The call stack tracks active execution contexts. When a function is called, its execution context is pushed onto the stack. When the function returns, that context is normally popped from the stack.
Is an execution context the same as scope?
No. An execution context manages the execution of code, while scope determines where identifiers can be accessed. Execution contexts use lexical environments and related mechanisms to resolve variable references.
Conclusion
JavaScript execution context explains how the engine prepares and executes code. The global execution context handles top-level code, while function execution contexts handle individual function calls.
The execution context lifecycle consists of preparation, execution, and completion. The call stack tracks active contexts as functions are called and return.
Understanding execution context makes it easier to learn hoisting, scope, closures, function calls, and asynchronous JavaScript.