Closures

  • This lesson explains how closures work and why they are powerful.
  • Introduction to Closures

    Closures are one of the most important and powerful concepts in JavaScript.
    They are frequently asked in interviews and widely used in real-world applications, especially in:

    • DOM event handling

    • Data privacy

    • Callbacks

    • Timers

    • Modular code

    Understanding closures properly will help you write cleaner, safer, and more efficient JavaScript code.

    What is a Closure ?

    Simple Definition

    A closure is created when a function remembers and accesses variables from its outer (parent) scope, even after the outer function has finished executing.

    Technical Definition

    A closure is a function that has access to:

    1. Its own scope

    2. Its outer function’s variables

    3. Global variables

    Even after the outer function has returned.

    Why Are Closures Important ?

    Closures allow JavaScript to:

    • Preserve data

    • Maintain state

    • Implement private variables

    • Control access to variables

    • Avoid global pollution

Understanding Closures in JavaScript

Explains how functions access and modify variables from outer scope

// Without closure (global variable)
let count = 0;

function increment() {
  count++;
  console.log(count);
}

increment(); // 1
increment(); // 2
  • Problem:

    • count is global

    • Can be modified from anywhere

Closure for Data Encapsulation and State

Uses closure to preserve and protect a private variable across function calls

function counter() {
  let count = 0;

  return function () {
    count++;
    console.log(count);
  };
}

let increment = counter();

increment(); // 1
increment(); // 2
increment(); // 3
  • How Closure Works 

    1. counter() is called

    2. count is created inside counter()

    3. Inner function is returned

    4. counter() finishes execution

    5. count is NOT destroyed

    6. Inner function remembers count

    This memory is called a closure.

    Important Point to Remember

    Even though the outer function is finished,
    its variables stay alive because the inner function still needs them.

How Closure Remembers Variables Internally

Explains how inner functions retain access to outer variables even after execution

// Visual representation of closure
counter() {
  count = 0   // remembered by inner function

  return function () {
    count++;  // still accessible
  }
}
  • The returned function closes over the variable count.

Using Closures with Function Parameters

Creates customized functions by remembering parameter values

function multiplier(factor) {
  return function (number) {
    return number * factor;
  };
}

let double = multiplier(2);
let triple = multiplier(3);

console.log(double(5)); // 10
console.log(triple(5)); // 15
  • Each function remembers its own factor.

    Closures and DOM

    Closures are heavily used in DOM event handling.

Using Closures in DOM Event Handling

Maintains state across button clicks using closure

<!-- HTML -->
<button id="btn">Click Me</button>

<script>
// JavaScript
function clickCounter() {
  let count = 0;

  document.getElementById("btn").addEventListener("click", function () {
    count++;
    console.log("Clicked:", count);
  });
}

clickCounter();
</script>
  • Here:

    • count is private

    • Only accessible through the event handler

    • Closure keeps it alive

Closures with let in Loops

Preserves correct values in asynchronous callbacks using block scope

for (let i = 1; i <= 3; i++) {
  setTimeout(function () {
    console.log(i);
  }, 1000);
}
// Output after 1 second: 1 2 3
  • let creates a new block scope automatically.

    Use Cases of Closures

Data Privacy Using Closures

Protects private variables and allows controlled access through functions

function bankAccount() {
  let balance = 1000;

  return {
    deposit(amount) {
      balance += amount;
      console.log(balance);
    },
    withdraw(amount) {
      balance -= amount;
      console.log(balance);
    }
  };
}

let account = bankAccount();

account.deposit(500); // 1500
  • balance cannot be accessed directly.

Execute Function Only Once Using Closure

Ensures a function runs only once by storing state in a closure

function once() {
  let executed = false;

  return function () {
    if (!executed) {
      console.log("Executed once");
      executed = true;
    }
  };
}

let runOnce = once();

runOnce(); // Executed once
runOnce(); // no output
  • Function Factories

Create Functions Dynamically Using Function Factories

Generates customized functions by using closures with parameters

function greeting(language) {
  return function (name) {
    console.log(language + " " + name);
  };
}

let english = greeting("Hello");
let hindi = greeting("Namaste");

english("Rahul");  // Hello Rahul
hindi("Switty");   // Namaste Switty
  • Closures and Memory 

    Closures keep variables in memory.

    Poor usage can cause:

    • Memory leaks

    • Unused data retention

    Best Practices for Closures

    • Use closures only when needed

    • Avoid large data inside closures

    • Remove event listeners when not required

    • Prefer let and const

    • Keep closures readable

    Common Beginner Mistakes

    • Thinking closures copy values (they don’t)

    • Forgetting closures hold references

    • Overusing closures unnecessarily

    • Confusing scope and closure

    Key Points to Remember

    • Closures are created automatically

    • Functions remember their lexical scope

    • Closures help in data hiding

    • Widely used in DOM and callbacks

    • Essential for advanced JavaScript