JavaScript Closures

August 31, 2026 Categories: Development

The first type of JavaScript most developers learn (procedural programming) is functions that run when they are called, and wait to be called again. Variables are forgotten at the end of the call, to be created again next time. A closure can be thought of as JavaScript that persists after it has been initialized. Internal state is maintained, such as variable values and event bindings. If there are multiple instances, each has its own memory space so each has its own variables and bindings.

MDN’s Definition of Closures
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 a function access to its outer scope.

When you’re used to working with procedural JavaScript, the jump to Closures can seem like a philosophical discussion about time-travel paradox. Seeing it in action tends to be the best way to understand it. A basic closure could be used as a counter, to track the number of people walking into a theater, for example. In procedural JS, that would look like a global variable and a button that calls the increment function.

var entries = 0; function incCounter() { entries++; // Do something to present the value of entries, like update the contents of a span. }

That works fine for a simplified example like this, but the risk is that some other function could mistakenly update the shared global value of entries. It is the responsibility of the developer(s) to make sure they don’t overwrite that value elsewhere. Written as a closure, each instance of the counter has its own protected entries variable that nothing else can touch. With the code below, just add a click event on a button that calls clicker_1.inc and you’re in business.

let simpleCounter = function() { let entries = 0; simpleCounter.inc = incCounter; return simpleCounter; function incCounter() { entries++; console.log(entries); } } const clicker_1 = simpleCounter(); clicker_1.inc();

Using this method, you could easily create multiple clickers and manage their values independently. Since their variables are protected, no other code can accidentally overwrite the entries value.

To take this to the next level, let’s build a cooking timer that supports multiple timers at once so you can track the steaks, french fries and frozen side dish all independently. Each timer will be an instance of simpleCounter, but we’ll add the click event and a method to display the timer.

This version adds an interface, allowing you to create multiple timers which all run independent of each other. When the timer runs out, you have the option to delete or restart it.

let timerClosure = function (targetElement, timerLabel='Timer', timerMins,) { const outputDiv = document.getElementById(targetElement); let wrapper, txtNode, span; wrapper = document.createElement("div"); span = document.createElement("span"); span.textContent = timerMins; txtNode = document.createTextNode(`${timerLabel} = `); wrapper.appendChild(txtNode); wrapper.appendChild(span); outputDiv.appendChild(wrapper); const interval = setInterval(() => { if (timerMins >= 0) { span.textContent = timerMins; } else { span.textContent = 'FINISHED!'; clearInterval(interval); } --timerMins; }, 60000); return timerClosure; }; const addBtn = document.getElementById("addTimerBtn"); addBtn.addEventListener("click", function (e) { const label = document.getElementById("TimerLabel").value; const mins = document.getElementById("mins").value; new timerClosure("collectionWrapper",label, mins); });

Cooking Timer In Action

Minutes