JavaScript Closures Explained Like You’re Five
Anil kumawat

Anil kumawat @anil_kumawat

About: 👋 Hey there! I'm Anil Kumawat, a passionate full-stack developer (MERN stack )who loves building web apps and exploring how things work under the hood. Let’s connect and build something awesome! 😃.

Joined:
Mar 3, 2025

JavaScript Closures Explained Like You’re Five

Publish Date: Mar 3
1 0

Closures are one of the trickiest yet most fundamental concepts in JavaScript. If you’ve ever found yourself confused about why certain variables persist after a function has executed, then you’re in the right place. Let’s break it down in the simplest way possible.


What Are Closures?

Closures occur when a function remembers the variables from its surrounding scope even after that scope has exited. In simple terms, a closure allows a function to access variables from its parent scope even after the parent function has finished executing.

Think of it like this:
Imagine you visit a bakery and order a custom cake. The baker (function) takes your order (variables), goes into the kitchen (parent function execution ends), and later comes back with your cake (accessing variables). The baker still remembers what you ordered even though you are no longer at the counter!


Understanding Scope & Lexical Environment

To understand closures, we first need to understand scope.

1. Global vs. Function Scope

let globalVar = "I am global";

function testFunction() {
    let localVar = "I am local";
    console.log(globalVar); // ✅ Accessible
    console.log(localVar);  // ✅ Accessible
}

console.log(globalVar); // ✅ Accessible
console.log(localVar);  // ❌ Error: localVar is not defined
Enter fullscreen mode Exit fullscreen mode

Variables declared inside a function cannot be accessed from outside. But closures allow us to work around this limitation.

2. Lexical Scope & Closures

JavaScript uses lexical scoping, meaning functions can access variables from their parent scope.

function outerFunction() {
    let outerVar = "I am from outer function";

    function innerFunction() {
        console.log(outerVar); // ✅ Accessible due to closure
    }

    return innerFunction;
}

const myClosure = outerFunction();
myClosure(); // Output: "I am from outer function"
Enter fullscreen mode Exit fullscreen mode

Here, innerFunction retains access to outerVar even after outerFunction has finished executing.


How Closures Work (With Examples)

Example 1: A Simple Closure

function makeCounter() {
    let count = 0;
    return function () {
        count++;
        console.log(count);
    };
}

const counter = makeCounter();
counter(); // Output: 1
counter(); // Output: 2
Enter fullscreen mode Exit fullscreen mode

Even though makeCounter() has finished execution, the returned function retains access to count because of closures.

Example 2: Closures in setTimeout

function delayedMessage(msg, delay) {
    setTimeout(function() {
        console.log(msg);
    }, delay);
}

delayedMessage("Hello after 2 seconds!", 2000);
Enter fullscreen mode Exit fullscreen mode

The inner function inside setTimeout remembers the msg variable, even though delayedMessage has already executed.


Real-World Use Cases of Closures

Closures are not just a theoretical concept; they have practical applications in JavaScript programming.

1. Data Encapsulation (Creating Private Variables)

Closures help us create private variables, making them inaccessible from outside.

function secretMessage() {
    let secret = "I am hidden";
    return function() {
        console.log(secret);
    };
}

const revealSecret = secretMessage();
revealSecret(); // Output: "I am hidden"
console.log(secret); // ❌ Error: secret is not defined
Enter fullscreen mode Exit fullscreen mode

2. Function Factories & Currying

Closures allow us to create customized functions dynamically.

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

const double = multiplier(2);
console.log(double(5)); // Output: 10

const triple = multiplier(3);
console.log(triple(5)); // Output: 15
Enter fullscreen mode Exit fullscreen mode

3. Memoization for Performance Optimization

Closures help in caching results to optimize performance.

function memoizedAdd() {
    let cache = {};
    return function (num) {
        if (num in cache) {
            console.log("Fetching from cache");
            return cache[num];
        }
        console.log("Calculating result");
        let result = num + 10;
        cache[num] = result;
        return result;
    };
}

const addTen = memoizedAdd();
console.log(addTen(5)); // Output: Calculating result, 15
console.log(addTen(5)); // Output: Fetching from cache, 15
Enter fullscreen mode Exit fullscreen mode

Common Mistakes & Debugging Closures

1. Unintended Memory Leaks

Since closures hold references to variables, they can cause memory leaks if not handled properly.

function leakyFunction() {
    let bigArray = new Array(1000000).fill("I am a big array");
    return function () {
        console.log(bigArray.length);
    };
}

const leakyClosure = leakyFunction();
// The large array remains in memory even if it's not needed!
Enter fullscreen mode Exit fullscreen mode

💡 Solution: Avoid holding unnecessary large variables inside closures.

2. Scoping Issues in Loops

A common mistake occurs when using var inside loops.

for (var i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}
// Output: 4, 4, 4 (not 1, 2, 3!)
Enter fullscreen mode Exit fullscreen mode

💡 Solution: Use let instead of var to ensure proper block scoping.

for (let i = 1; i <= 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, i * 1000);
}
// Output: 1, 2, 3 ✅
Enter fullscreen mode Exit fullscreen mode

Conclusion

Closures are a fundamental concept in JavaScript that allow functions to remember their parent scope even after execution. They play a crucial role in data encapsulation, function factories, memoization, and asynchronous programming.

Key Takeaways:
✅ Functions retain access to their outer scope due to closures.
✅ Closures help create private variables, optimized functions, and better performance.
✅ Be mindful of memory leaks and scoping issues when using closures.

By mastering closures, you'll level up your JavaScript skills and write cleaner, more efficient code!

🚀 Recommended Reading:

Comments 0 total

    Add comment