Closures are a fundamental and misunderstood part of JavaScript. No less an authority than Douglas Crockford has called them “maybe the best feature ever put in a programming language.”

In this article I’ll explain what closures really are, discuss how they can be used to make private methods, and explain the classic for loop gotcha around them.

Closures

A closure occurs whenever an inner function has access to the variables in an outer function.

Consider what happens when a function tries to access a variable that has not been defined.

function example() {
  console.log(name);
}

example(); // ReferenceError: name is not defined

It yields an error! You can’t reference a variable, in this case name, that has not been defined.

But look what happens if our function is nested inside an outer function that does have a variable name.

function outerFunc() {
  let name = 'William';
  function innerFunc() {
    console.log(name);
  }
  innerFunc();
}

outerFunc(); // 'William'

The outer function outerFunc has its own variable name. The inner function innerFunc, when executed, will try to log that same variable. So we execute the function innerFunc within our outerFunc. Therefore the chain of execution is we call outerFunc which proceeds to call innerFunc which magically does have access to the variable name even though the variable is only found in the outer function. not the inner function itself.

The JavaScript interpreter–which runs our program–has looked within innerFunc for a variable name, and not finding it, the interpreter then looks in the outer enclosing (hence the term “closure”) function and sees that outerFunc does have a variable name, so that is what’s used.

In this way the inner function always has access to an outer function’s variables.

Now what happens if an inner and outer function have the same variable name?

function outerFunc() {
  let name = 'William';
  function innerFunc() {
    let name = 'Ashley';
    console.log(name);
  }
  innerFunc();
}

outerFunc(); // 'Ashley'

The JavaScript interpreter still looks for the variable name within the inner function first, finds it, and uses that. There is no need to keep looking in the outer function.

Global Scope

Another confusing aspect of closures is that in JavaScript technically every function is a closure. The reason is that JavaScript is never run just on its own, it is always run in the context of either a web browser or on a server via Node. Both a web browser and Node have their own global scope which enclose all inner functions.

So even if we just declare one single function, there is always another outer, global function available. Therefore every function is a closure.

Consider this example.

let z = 'Hello';

function sayHi() {
  console.log(z);
}

z; // 'Hello'

This is a closure. We are referencing a variable z with our sayHi function that was set in an outer function. It’s just that said outer function is the global scope here.

Here’s one more example of global and local scope:

let x = 'global';

function myFunc() {
  let y = 'local';
  console.log(x + ' and ' + y + 'scope');
}

myFunc(); // 'global and local scope'

The global scope acts like an outer function that encloses inner, local-scoped functions.

For loops

Closures are also present in for loops, which are a classic interview question for JavaScript developers. Here is one that outputs the numbers 1-5.

for (var i = 1; i < 6; i++) {
  console.log(i); // 1 2 3 4 5
}

So far so good. Now here’s the tricky part: what is the value of i? You’re probably thinking 5 but the answer is 6. The reason is closures.

Our for loop uses var which is function-scoped, however we are not using a function for our loop. So where is the name binding for our variable i? The answer is the enclosing, global scope. The variable i exists as a global variable in our browser window.

The for loop executes via three clauses:

  • Initialization: var i = 1
  • Conditional: i < 5
  • Update: i++

But the order in which they are executed is Initialization -> Update -> Conditional. Or first, third, second. Each time through the for loop starts with an initial value, updates it, checks if the condition is true, and if so then console.log’s the result.

So on the last pass through var i = 5, then i is incremented to 6, and the conditional clause 6 < 5 fails. So the loop stops. However i is set to 6! And since i is a global variable, we have access to it outside of the for loop itself, and the value is 6 even though the last output of our loop is 5.

Private Methods/Variables

Perhaps the most common and powerful use of closures in JavaScript is as a way to make inner variables/functions private. This is often implemented using the Module Pattern which Todd Motto describes brilliantly.

Conclusion

And that’s really it. A closure occurs in JavaScript whenever an inner function has access to the variables/scope of an outer, enclosing function.




Want to improve your JavaScript? I have a list of recommended JavaScript books.