I know what you're about to say. I, too, have read dozens of posts on JavaScript closures. But closures haven't really clicked for me until I read the MDN page three times then attempted to explain the concept to my mentor, @tryggvigy. Everything I learned from our conversation is written below.
What is a closure
One of the reasons I couldn't get a good grasp on closures is because they don't mean anything to me in a regular context. In plain English, a closure is the process or act of closing something, and what am I gonna close in JavaScript except for my editor when I get one too many undefined is not a function
errors?
People have different ways of explaining what a closure is. The short version is that a closure is a function's ability to access variables that are defined outside of it. If we have a function B inside another function A, any variables that are defined in function A can be accessed by function B.
function A() {
const one = 1;
const two = 2;
function B() {
console.log(`${one} plus ${one} equals ${two}`);
}
B();
}
A();
The above will log "1 plus 1 equals 2". This snippet calls function B inside of function A, so that function B executes whenever function A is called, such as in the last line.
A useful attribute of closures is that they create variables that are private to a function. For example, the variable one
cannot be accessed outside of function A. This encourages us to declare variables only in the scope we need them in, and avoid unnecessary global variables.
Naming
Now that we understand what closures are, why did they choose to call them that? Some people say that function A closes over function B, since it is effectively protecting it from being read elsewhere in the code.
And that's it for closures! But we can go a little bit further and relate them to two more concepts in JavaScript that are very closely related: higher order functions and lexical scope.
Higher order functions
Most examples I've seen online will not look like the previous one, but will instead utilize higher order functions. A higher order function is a function that returns another function. Since higher order functions include outer and inner functions by definition, this means that every higher order function uses closures. However, not every function that has a closure is a higher order function, like we saw in the first example. The same snippet can be rewritten to use higher order functions:
function A() {
const one = 1;
const two = 2;
return function B() {
console.log(`${one} plus ${one} equals ${two}`);
}
}
A()();
In this case, using A()
will return the body of function B, so we're using A()()
in order to execute function B.
I'm using ES5 syntax but all of these concepts exist in ES6 as well.
const A = () => {
const one = 1;
const two = 2;
return B => {
console.log(`${one} plus ${one} equals ${two}`);
}
}
A()();
Lexical scope
The other concept is lexical scope. I'm not even sure what lexical means, but in JavaScript, a function's scope starts from its opening curly bracket and ends with its closing bracket.
The innermost white bracket in the image is the local scope of function B. The middle red bracket is the local scope of function A, and the identical green line is the lexical scope of function B.
That's because the lexical scope of a function is the function's own local scope plus the local scope of its surrounding function(s). This means that the local scope of an outer function equals the lexical scope of an inner function.
Now we can rewrite our definition of closures from a function's ability to access variables declared outside of it to a function's ability to access variables in its lexical scope. Some definitions even equate a closure with the function's lexical scope.
Every function has a closure and lexical scope, even if it doesn't have a visible outer function. For instance, in front-end JavaScript, any function that you write has access to the global window
variable because it's in its lexical scope.
TL;DR
- A closure is a function's ability to access variables declared outside of it (or in its lexical scope)
- By definition, all higher order functions use closures
- Lexical scope of a function is the function's local scope plus the local scope of any surrounding functions
Thanks for reading! Until next time đź‘‹
Cover photo by Paweł Czerwiński on Unsplash
Top comments (0)