I've had "explain closures" sitting in my drafts folder since October, right after I finally admitted to myself I'd been using them for two years without really being able to define one out loud. Every tutorial I found online does the same thing: it shows you a function returning a function, says "see, the inner function remembers the outer variable," and then just... stops. No context for why you'd ever want that. So here's my attempt at explaining it with stuff you'd actually type into a real project, not a toy example that only exists to prove a point.
The boring definition first, then we move on
A closure happens when a function keeps access to variables from the scope it was created in, even after that outer scope has technically finished running. That's it. JavaScript does this automatically, you don't opt in or configure anything, which is honestly the part that used to confuse me most. It just happens, all the time, whether you notice or not.
Example one: the counter that actually gets used
Say you're building a little UI widget, a "load more" button for a comment thread (I built almost exactly this for a client site last month). You want a counter that tracks how many times someone's clicked it, but you don't want that number sitting around as a global variable where any other script on the page could mess with it.
function makeClickCounter() {
var count = 0;
return function() {
count = count + 1;
return count;
};
}
var loadMoreClicks = makeClickCounter();
loadMoreClicks(); // 1
loadMoreClicks(); // 2
loadMoreClicks(); // 3
The count variable lives inside makeClickCounter, but the function you get back still has a reference to it. Nothing outside can touch count directly. No window.count, no accidentally clobbering it from some other jQuery plugin on the page. That's a closure doing real work: it's giving you private state without needing a class or an object with this all over it.
Example two: the loop bug that trips up literally everyone
This is the one that actually made me understand closures, because I hit it myself and spent about forty minutes confused. Say you've got five buttons and you want each one to alert its own number when clicked.
for (var i = 1; i <= 5; i++) {
document.getElementById('btn' + i).onclick = function() {
alert('You clicked button ' + i);
};
}
Click any button, doesn't matter which one, and you get "You clicked button 6." Every single time. This drove me nuts the first time I ran into it (I think I was building a photo gallery thumbnail row, of all things). The problem is that var doesn't create a new scope for each loop iteration, there's just one i, shared by all five click handlers, and by the time anyone actually clicks a button the loop has already finished and i is sitting at 6.
The fix is to force a new scope on each pass through the loop, so each handler closes over its own copy:
for (var i = 1; i <= 5; i++) {
(function(num) {
document.getElementById('btn' + i).onclick = function() {
alert('You clicked button ' + num);
};
})(i);
}
That immediately-invoked function takes i as an argument and calls it num inside, so each click handler gets its own private num that never changes after the fact. Ugly looking, sure, but it works and it's everywhere in real code once you start looking for it.
I keep hoping the language just adds a proper block-scoped variable someday so this whole dance becomes unnecessary, but I'm not holding my breath, browser vendors move at their own pace and half of us are still stuck supporting IE7 for work reasons I don't want to get into right now.
One more thing worth saying: closures aren't free. Every one you create hangs onto its outer variables in memory for as long as something references the inner function. I've seen people wire up closures inside long-running loops or recurring setInterval calls without thinking about it, and the memory just creeps up over an hour of the page being open. Not a huge deal for a five-button gallery. A bigger deal if you're building something that runs all day, which, with all the SOPA hearing coverage I've had open in browser tabs for a week straight, mine currently is.
Anyway. If you only take one thing from this: any time an inner function outlives the call that created it and still reaches back into that call's variables, you're looking at a closure. You've probably already written a dozen without naming them.