Gyaan

Execution Context

intermediate execution-context hoisting scope-chain call-stack

Every time JavaScript runs code, it creates something called an Execution Context. Think of it as a box that holds everything the code needs to run — the variables, functions, and the value of this.

Two types of Execution Context

  1. Global Execution Context (GEC) — Created when the script first runs. There’s only one. It creates the window object (in browsers) and sets this to window.
  2. Function Execution Context (FEC) — Created every time a function is called. Each function gets its own execution context.

Two phases of every Execution Context

Every execution context goes through two phases:

1. Creation Phase (Memory Allocation)

Before running a single line of code, JavaScript scans the code and:

  • Allocates memory for variables and sets them to undefined
  • Stores the entire function declarations in memory
  • Determines the value of this
  • Sets up the Scope Chain (reference to the outer environment)

This is why hoisting works — variables and functions are already in memory before the code runs.

2. Execution Phase

Now JavaScript goes through the code line by line:

  • Assigns actual values to variables
  • Executes function calls (which create new execution contexts)
  • Runs all the logic
var name = "Manish";
function greet() {
  var message = "Hello";
  console.log(message + " " + name);
}
greet();

// Creation Phase:
//   name → undefined, greet → full function, this → window
// Execution Phase:
//   name → "Manish", greet() called → new execution context created

The Call Stack

JavaScript uses a Call Stack to manage execution contexts. When a function is called, its execution context is pushed onto the stack. When it returns, it’s popped off.

Call Stack (grows upward)
inner() EC
pushed when inner() is called
outer() EC
pushed when outer() is called
Global EC
always at the bottom, created first
When inner() finishes → popped off → back to outer() → popped off → back to Global
function outer() {
  var a = 10;
  function inner() {
    var b = 20;
    console.log(a + b); // 30 — inner can access outer's variables via scope chain
  }
  inner(); // new execution context pushed onto stack
}
outer(); // new execution context pushed onto stack

Variable Environment and Scope Chain

Each execution context has a Variable Environment — the place where its local variables live. It also has a reference to its outer environment (the parent scope). This chain of references is the Scope Chain.

When JavaScript needs to find a variable, it first looks in the current Variable Environment. If it’s not there, it follows the Scope Chain upward until it either finds the variable or reaches the Global scope.

var global = "I'm global";

function first() {
  var a = "I'm in first";
  function second() {
    var b = "I'm in second";
    console.log(b);      // found in current scope
    console.log(a);      // found via scope chain (first's scope)
    console.log(global); // found via scope chain (global scope)
  }
  second();
}
first();

In simple language, every time JavaScript runs your code or calls a function, it creates a little environment with two phases — first it sets up memory (creation), then it runs the code (execution). These environments stack on top of each other in the Call Stack, and each one can look up to its parent for variables it doesn’t have locally.