No history yet

Execution and Scope

The Execution Context

Every line of JavaScript you write runs inside an environment called an execution context. Think of it as a wrapper that manages your code. The most fundamental one is the Global Execution Context (GEC), which is created the moment your script starts to run. It's the default context where any code outside a function lives.

Every line of JavaScript runs inside an Execution Context — this is the foundation of how JS works.

Every execution context is created in two phases:

  1. Creation Phase: The JavaScript engine scans your code, finds all the function and variable declarations, and sets aside memory for them. This is where hoisting happens.
  2. Execution Phase: The engine runs your code line by line, assigning values to variables and executing function calls.

Hoisting in Detail

Hoisting is the result of the Creation Phase. The engine "hoists" declarations to the top of their scope. However, how it treats them differs significantly based on the keyword used.

// `var` is hoisted and initialized with `undefined`.
console.log(myVar); // Outputs: undefined
var myVar = 10;

// Function declarations are fully hoisted (name and body).
hello(); // Outputs: "Hello World!"

function hello() {
  console.log("Hello World!");
}

With let and const, things are different. While their declarations are also hoisted, they are not initialized. Accessing them before their declaration results in a ReferenceError. The time between entering their scope and their declaration line is known as the Temporal Dead Zone (TDZ).

// `let` and `const` are in the Temporal Dead Zone.
// console.log(myLet); // Throws ReferenceError
let myLet = 20;

// Function expressions are not hoisted like declarations.
// myFunc(); // Throws TypeError: myFunc is not a function
var myFunc = function() {
  console.log("This is an expression.");
};

Notice the TypeError for the function expression. The variable myFunc is hoisted as a var and is undefined when called, not a function.

The Call Stack

When your script runs, the Global Execution Context is placed at the bottom of the call stack. Every time a function is called, a new Function Execution Context is created and pushed onto the top of the stack.

The JavaScript engine always executes whatever is at the top of the stack. When a function finishes, its context is popped off the stack, and control returns to the context below it.

This Last-In, First-Out (LIFO) process continues until the stack is empty, which means the script has finished.

Where Variables Live

So where are these variables and functions stored? Each execution context has a corresponding Lexical Environment. This is the local memory for that context.

A Lexical Environment has two main parts:

  1. Environment Record: The dictionary where your local variable and function declarations are stored.
  2. Reference to the Outer Environment: A link to the lexical environment of its parent. For a function, this is the environment where the function was defined, not where it was called.

This link to the outer environment is what creates the Scope Chain a fundamental concept in JavaScript. When you use a variable, the engine first looks for it in the current lexical environment. If it can't find it, it follows the reference to the outer environment and looks there. This continues all the way up to the global scope. If it's not found there, you get a ReferenceError.

Let's trace an example.

const globalVar = 'I am global';

function outerFunction() {
  const outerVar = 'I am in outer';

  function innerFunction() {
    const innerVar = 'I am in inner';
    console.log(innerVar);    // Found in innerFunction's scope
    console.log(outerVar);    // Found in outerFunction's scope
    console.log(globalVar);   // Found in the global scope
  }

  innerFunction();
}

outerFunction();

When innerFunction is executed, its lexical environment contains innerVar. When it needs outerVar, it doesn't find it locally, so it follows the link to outerFunction's environment, where it finds it. The same process happens for globalVar.

Ready to test your knowledge? Let's see how well you can trace the code.

Quiz Questions 1/6

What is the most fundamental execution context created when a JavaScript script starts to run?

Quiz Questions 2/6

The time between entering the scope of a let or const variable and its actual declaration is known as the __________.

Understanding these core mechanics is crucial. It demystifies why your code behaves the way it does and helps you write cleaner, more predictable, and less buggy JavaScript.