Understanding Lexical Scope and Scope Chain in JavaScript

What is Scope?

Scope refers to the visibility and accessibility of variables (var, let and const) in different parts of the code. In JS, scope is primarly categorized into:

  1. Gloabl Scope - Variables decalred outside of any function are accessible anywhere in the code.
  2. Function Scope - Variables declared inside a function are assessible only within that function.
  3. Block Scope - Variables declared with let and const inside a block {} are only accessible within that block, whereas var is function-scope and does not have block-level scope.

Lexical Scope (Static Scope)

Lexical scope means that the accessibility of varibales is determined at the time the code is written, not when it is executed. Meaning, a function can access variables from its own scope, its parent function's scope, and any outer scope where it was originally defined, regardless of where or when it is executed. This means that when a function is created inside another function, it remembers the variables available in its surrounding scope at the time of definition.

Example:


function outerFunction() {
    let outerVariable = "Outer Variable";

    function innerFunction() {
        console.log(outerVariable); // Can access outerVariable due to lexical scope
    }

    innerFunction();
}

outerFunction(); // Output: Outer Variable

Scope Chain and Nested Scope

In JS, Scopes are nested. Scope Chain is the mechanism that determines how varibales are resolved when a function is executed. When a variable is not found in the local scope, JavaScript looks up through outer scopes. If it finds the variable, uses it, otherwise it throws a ReferenceError.


const globalVar = "Global Variable"; // Global scope

function outer() {
    const outerVar = "Outer Variable"; // Outer function scope

    function inner() {
        const innerVar = "Inner Variable"; // Inner function scope

        console.log(innerVar);  // Found in inner()'s local scope
        console.log(outerVar);  // Found in outer()'s scope (parent scope)
        console.log(globalVar); // Found in global scope
    }

    inner();
}

outer();
// Inner Variable
// Outer Variable
// Global Variable