A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
One of the most common uses of closures is data privacy. We can create variables inside a function that cannot be accessed from outside.
createCounter() scope
let count = 0 (private)
increment()
count++ ✓
getCount()
return count ✓
Outside: count ✗ ReferenceError
function createCounter() {
let count = 0; // private variable, not accessible from outside
return {
increment: function() {
count++;
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.getCount()); // 2
// console.log(count); // ReferenceError: count is not defined
A very common interview question is closures inside loops. When we use var in a loop with setTimeout, all the callbacks share the same i variable, so they all print the final value instead of each value.
// Problem with var
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// Output: 3, 3, 3 (all reference the same i)
// Fix with let (block-scoped, creates new binding each iteration)
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
// Output: 0, 1, 2