JavaScript Execution Context

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 to 10.
  • JavaScript calls calculate() and creates a function execution context.
  • Inside the function, the local number is initialized to 20.
  • 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.

FeatureGlobal Execution ContextFunction Execution Context
CreationCreated when program execution beginsCreated whenever a function is called
Code handledTop-level codeCode inside a function call
VariablesManages global-scope bindingsManages local bindings and parameters
Number createdGenerally one per script or module executionA new one for each function call
LifetimeUsually lasts throughout the script’s executionUsually lasts until the function returns, unless execution is suspended
Call stackInitial context for executionAdded 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 to second() 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 number is initialized to 5.
  • JavaScript reaches the call to multiply(number).
  • A function execution context is created, with value set to 5.
  • The local variable result is initialized to 10.
  • The function returns 10, and its execution context leaves the call stack.
  • The global binding answer is 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.