Outer scope
The variables available where the function is created.
A closure happens when a function remembers variables from the scope where it was created, even after that outer function has finished.
function createCounter() {
let count = 0;
return function () {
count += 1;
return count;
};
}
const next = createCounter();
console.log(next());
Functions & Scope
A closure is created when an inner function uses variables from an outer scope. The inner function keeps access to those variables later.
Closures are not rare or advanced magic. They appear in event handlers, timers, factory functions, modules, callbacks and stateful utilities.
The power of closures is private memory. The risk is accidental memory or stale values when a function keeps more data alive than expected.
The variables available where the function is created.
The function that keeps access to those variables.
State hidden from direct outside access.
A function that returns configured behavior.
Examples
function createCounter() {
let count = 0;
return {
next() {
count += 1;
return count;
}
};
}
let count = 0;
function next() {
count += 1;
return count;
}
// Any code can now change count.
Code patterns
These examples focus on syntax you will actually look up later: declarations, callbacks, returns, closures and context handling. Use the small patterns first, then study the deeper explanation.
Keep state without a global variable.
function createCounter() {
let count = 0;
return () => {
count += 1;
return count;
};
}
Create a configured function.
function createPrefixer(prefix) {
return (value) => `${prefix}: ${value}`;
}
const status = createPrefixer("Status");
console.log(status("ready"));
Expose methods while keeping data private.
function createStore() {
const items = [];
return {
add(item) { items.push(item); },
count() { return items.length; }
};
}
A handler can keep local state across clicks.
function attachCounter(button, output) {
let count = 0;
button.addEventListener("click", () => {
count += 1;
output.textContent = count;
});
}
Rules that matter
Functions are where JavaScript stops being a list of statements and becomes a system. Scope decides what each function can see, while return values and parameters decide how functions communicate.
The inner function keeps access to outer variables.
Factory functions can hide implementation details.
Do not close over large data unless it is needed.
createCounter and createStore communicate stateful behavior.
let gives each loop iteration its own binding.
Closures are useful, but not every variable needs privacy machinery.
Production thinking
Closures explain why callbacks can remember values. Once that clicks, many JavaScript patterns become much less mysterious.
Stateful UI helpers can use closures to keep state local while updating accessible text and attributes.
Production closures should keep state private without hiding too much behavior or retaining unnecessary memory.
Rendering factories can keep configuration local, but output should still be deterministic and testable.
Live code lab
The preview runs inside an isolated iframe. The JavaScript is placed inside the HTML editor for now, so every example stays together and remains easy to understand.
Mini assignment
Practice assignment
Try it yourself
Self-check
Functions only become useful when you can explain what goes in, what comes out and which scope the function can see.
Senior audit upgrade
A closure is not magic. An inner function keeps access to variables from the outer function after the outer function has returned.
outer function creates variable -> inner function uses it -> inner function is returned -> variable stays reachable through the closure