JavaScript ES2024 ·
✓ verified by execution on 2026-08-15
A closure is one of the most powerful and frequently misunderstood concepts in JavaScript. Simply put, a closure is a function bundled together with its lexical environment. This means that an inner function always has access to the variables and parameters of its outer function, even after the outer function has finished executing.
Whenever you create a function in JavaScript, a closure is created at that exact moment. The function permanently captures a reference to the environment where it was born.
A closure maintains a live reference to its outer environment, even when passed somewhere else.
Accessing Outer Scope
Because of closures, an inner function gives you access to an outer function’s scope. Here is a basic example where the inner function displayName accesses the variable name defined in its parent function makeFunc.
javascript · visualize
function makeFunc() { const name = 'Mozilla'; function displayName() { console.log(name); } return displayName;}const myFunc = makeFunc();myFunc();
Mozilla
When myFunc is invoked, it still has access to name, even though makeFunc has already finished executing.
Emulating Private Methods
JavaScript historically didn’t have a native way to declare private methods. However, closures provide a clean way to emulate private state. The variables captured by the closure cannot be modified from the outside.
A very common edge case occurs when creating closures inside loops using var. Because closures capture variables by reference and not by value, and because var is function-scoped rather than block-scoped, all closures created inside the loop will point to the exact same variable. By the time they execute, the loop has already finished, and they all see the final value.
Predict the outputjavascript
Read the code. What exactly will it print? Commit to an answer before you look.
function createFuncs() { var arr = []; for (var i = 0; i < 3; i++) { arr.push(function() { console.log(i); }); } return arr;}const funcs = createFuncs();funcs[0]();funcs[1]();funcs[2]();
Output
3
3
3
You predicted
You might have expected this to print 0, 1, 2. Instead, because i was declared with var, there is only one i variable shared across all three closures. By the time the functions are called, the loop has finished and i has reached 3.
Using let instead of var fixes this entirely, because let creates a new block-scoped binding for every single iteration of the loop!
Edge Cases to Watch Out For
Shared Bindings: As shown in the loop trap, using var inside a loop creates a single binding shared by all loop iterations, causing all closures to see the final value. Use let to give each closure its own binding.
Stale State in React: Closures inside setTimeout or setInterval can retain stale state if you are not using functional state updates. The closure remembers the state exactly as it was when the timeout was declared.
Check yourself
What exactly does a closure capture?
Reveal answer
A live reference to the outer variable, reacting to changes. — A closure captures a reference to the variable, so if the variable changes, the closure sees the new value.
When are closures created in JavaScript?
Reveal answer
Every time any function is created. — Closures are created every time any function is created. All functions in JavaScript form closures over their lexical environment.
How do closures affect memory?
Reveal answer
They can cause memory leaks if the closure is retained unnecessarily, keeping the outer scope alive. — Closures maintain a live reference to their lexical environment, which prevents garbage collection of those variables and can cause memory leaks if not managed carefully.
Which variables does a closure have access to?
Reveal answer
Its local scope, the enclosing scope, and the global scope. — Every closure has access to its own local scope, the enclosing scope (which can be nested functions or blocks), and the global scope.
Challenges
Challenge 1 +20 XP
Create a function `createGreeting(greeting)` that returns a new function. The returned function should take a `name` and return a string combining the greeting and the name.
javascript
Test 1 — expects "Hello Alice"
Need a hint? (−25% XP)
Return an inner function that takes `name` as an argument and combines it with `greeting`.