Scoping in JavaScript

Scoping defines where variables are accessible in JavaScript. Scope is established when the code is written (at declaration time), not during function execution. This includes global scope (accessible everywhere), function scope (limited to a function), and block scope (limited to {} blocks with let and const).

Advanced Example with Nested Functions

let globalVar = "I am global";

function outerFunction(x) {
  let outerVar = "I am outer";
  function innerFunction(y) {
    let innerVar = "I am inner";
    function deepestFunction(z) {
      let deepestVar = "I am deepest";
      console.log(`${globalVar}, ${outerVar}, ${innerVar}, ${deepestVar}, ${x}, ${y}, ${z}`);
    }
    deepestFunction("Z value");
  }
  innerFunction("Y value");
  console.log(outerVar); // Accessible here
  // innerVar or deepestVar not accessible here
}

function anotherOuter(a) {
  let anotherVar = "I am another";
  outerFunction("X value");
  console.log(anotherVar); // Accessible here
  // outerVar, innerVar, deepestVar not accessible here
}

anotherOuter("A value");
  • Explanation:
    • globalVar is in global scope, accessible everywhere.
    • outerVar is in outerFunction’s scope, accessible within it and its nested functions.
    • innerVar is in innerFunction’s scope, accessible to it and deepestFunction.
    • deepestVar is limited to deepestFunction.
    • Parameters x, y, z, and a are scoped to their respective functions.
    • Scope is set at declaration, so outerVar is unavailable outside outerFunction, even after execution.

What is a Closure?

A closure occurs when a function retains access to its outer scope’s variables even after the outer function has finished executing. This allows inner functions to “close over” and use variables from their outer scope, enabling data privacy and state management.


Addressing the Global Variables Suggestion

Some might suggest making all variables global for easier access, but this is a bad practice. Global variables can cause naming conflicts, unintended side effects, and make debugging harder. They also risk memory leaks since they persist throughout the application’s lifetime, even after functions using them finish. If references linger (e.g., in cached data or event listeners), the garbage collector can’t free the memory, leading to leaks. To avoid this, limit global variables and clean up references when no longer needed.


Resources