Mastering JavaScript Closures: Straightforward Examples for Beginners


Before diving into the concept, let me first show you the code and help you understand why it behaves the way it does.
function parent() {
// 10 acre
let property = 10;
return function child() {
console.log("I have " + property + " acres of property");
}
}
parent()(); // Output: I have 10 acres of property
We know that JavaScript is a single-threaded language, which means it has one call stack.
When a function finishes executing — like parent()
here — it's removed from the stack, right?
So if parent()
is gone, how does the inner child()
function still remember the value of property
? 🤯
That’s happening because in JavaScript, functions can form closures — meaning they remember the variables from their lexical scope, even after the outer function has finished executing.
In our example, child()
was defined inside parent()
, so it "closes over" the property
variable.
As a result, even though parent()
has returned, child()
still has access to property
— because it was part of the scope where child()
was created.
Think of it like this:
👉 Even when theparent()
function "dies" (i.e., finishes executing), theproperty
still belongs to thechild()
function — because the child has a strong reference to it.
That’s exactly what a closure is:
A function that remembers the variables from the scope where it was created — even if that outer function has already finished executing.
In JavaScript, this is made possible because of lexical scoping — where functions “remember” the environment in which they were born.
⭐ Important Clarification:
Closure Keeps Reference, Not Value
A closure doesn't store a snapshot of the variable's value —
it keeps a reference to the original variable in memory.
So if the variable changes later, the closure will see the updated value.
function parent() {
let property = 10;
const child = function() {
console.log(property);
};
property = 100;
return child;
}
const childFn = parent();
childFn(); // 100 ✅ because it refers, not copies
In short: Closure = Function + Lexical Scope bundled together
Let’s Touch on Some Advanced Closure Concepts:
Now that we understand the basics of closures, let’s explore some more advanced and interesting scenarios where closures play a crucial role — including one of the classic “gotchas” that often trips up JavaScript developers: closures inside loops.
Closures Inside Loops — The Classic JavaScript Gotcha
One of the trickiest and most common problems involving closures happens when you use them inside loops.
Imagine you write a loop that schedules some functions to run later — like with setTimeout
. You might expect each function to remember the current loop value. But surprisingly, all the functions end up sharing the same final value instead!
Let’s see why this happens, and how understanding closures can help us fix it.
Closures Inside Loops
Consider this code snippet:
for (var i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// What do you think this will print?
You might expect it to print:
1
2
3
But surprisingly, it prints:
4
4
4
Why is that?
What’s Going On?
The reason lies in how closures and the var
keyword work together. The var
variable i
is function-scoped, so there is only one i
shared by all the functions inside the loop.
By the time the setTimeout
callbacks run (after 1 second), the loop has already finished, and i
has the value 4
(which caused the loop to stop).
All the closures reference the same i
, so they all print the same final value.
How to Fix the Closure Inside Loop Problem
Solution 1: Use let
Instead of var
The easiest and most modern way is to use let
for the loop variable, because let
is block-scoped. This means every iteration gets its own separate i
.
for (let i = 1; i <= 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// Output: 1 2 3
Each closure now remembers the value of i
for that particular iteration.
Solution 2: Use an Immediately Invoked Function Expression (IIFE)
If you want to support older JavaScript environments without let
, you can use an IIFE to create a new scope each iteration:
for (var i = 1; i <= 3; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
}, 1000);
})(i);
}
// Output: 1 2 3
Here, j
is a new parameter passed to the IIFE, capturing the current value of i
. Each closure then references its own copy j
.
Summary
Closures capture variables by reference, not value.
Using
var
causes closures in loops to share the same variable.Use
let
or an IIFE to create new scope for each iteration and fix the issue.
Why Are Closures So Powerful?
Closures are more than just a neat trick — they are fundamental to how JavaScript manages variables and functions:
Preserve State: Closures let functions “remember” variables from their creation context, even after the outer function has finished running.
Enable Data Privacy: They help us create private variables that can’t be accessed directly from outside.
Support Functional Programming: Closures are essential for patterns like currying, partial application, and higher-order functions — concepts we’ll explore in more detail later in this series.
Handle Asynchronous Code: They allow callbacks, promises, and event handlers to access the variables they need.
Understanding closures gives you deeper insight into JavaScript’s behavior and lets you write more elegant, bug-free code.
Quick Summary
A closure is a function bundled together with its lexical scope.
Closures allow inner functions to remember variables from their outer functions, even after those outer functions finish.
Variables inside closures are referenced, not copied, which affects behavior in loops.
Using
let
or IIFEs helps avoid common closure pitfalls in loops.
Final Thoughts
Closures may seem tricky at first, but once you grasp how they work, they become one of your most powerful tools in JavaScript. Remember, closures help functions remember their surrounding state, enabling you to write cleaner, more modular, and more expressive code.
Keep practicing with different examples, and soon you’ll see closures popping up everywhere in your projects!
If you found this post helpful, feel free to share it and follow me for more JavaScript tips and deep dives.
Happy coding! 🚀
Subscribe to my newsletter
Read articles from Mandeep Kaur directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Mandeep Kaur
Mandeep Kaur
Frontend Engineer 👩🏻💻 | Crafting seamless and responsive user interfaces with React & modern JavaScript | Passionate about clean code, UI/UX, and performance optimization | Sharing frontend tips, tricks, and tutorials