loading...
Cover image for What is Closure in JavaScript?

What is Closure in JavaScript?

brettfishy profile image Brett Fisher Originally published at brettfisher.dev ・2 min read

I recently purchased and read the book You Don't Know JS Yet by Kyle Simpson, which I found to be a great read. Even though I've worked as a JS developer for years, there were so many new things I learned by reading it (I am not endorsed by anyone affiliated with this book - I'm just recommending it because I genuinely liked it).

One of those things was "closure" - a term I had heard a couple of times but never understood what it actually meant. I think it's hard to beat Kyle Simpson's definition:

Closure is when a function remembers and continues to access variables from outside its scope, even when the function is executed in a different scope.

So, what does that look like?

Some Examples of Closure

You've probably already used closure before and just didn't realize it. Take the following example:

function doAsyncTask(successMsg) {
  someAsyncTask().then(() => {
    console.log(`I remembered your variable! ${successMsg}`);
  });
}

getSuperImporantInfo('Hooray!');

// Some time later...
// I remembered your variable! Hooray!

When someAsyncTask finishes executing, it prints out the successMsg variable passed to doAsyncTask. someAsyncTask could take several seconds or even several minutes to execute, but the callback function passed to then "remembers" the successMsg variable. We say the the callback function is "closed" over successMsg.

I've done things like this all the time, I just didn't know I was using closure!

Now let's say you want to create a counter function. Every time you call the function, it will return the next number after the last number it returned. You can use closure to "remember" the last number returned.

function createCounter() {
  let count = 0;
  return () => count++;
}

const inc = createCounter();

inc();
// 0
inc();
// 1
inc();
// 2

createCounter returns an anonymous function which has access to the count variable. The function returned by createCounter is "closed" over count. We can even create multiple increment functions, all of which will have their own copy of count.

const inc1 = createCounter();
const inc2 = createCounter();

inc1();
// 0
inc2();
// 0
inc1();
// 1
inc1();
// 2
inc2();
// 1

These may be simple examples, but I've certainly needed to write counter functions like this before. Before I knew about closure, I would create variables visible to my entire module and increment those in my counter function. Now I know there's a better way that doesn't require me polluting my modules' scopes.

That's all there is to it! What other examples can you think of where you could use closure to your advantage?

Posted on by:

brettfishy profile

Brett Fisher

@brettfishy

I'm a full stack web developer originally hailing from Colorado. I'm currently doing an internship with Amazon and study Computer Science at Brigham Young University.

Discussion

pic
Editor guide
 

Closure is when a function remembers and continues to access variables from outside its scope, even when the function is executed in a different scope.

This is somewhat incorrect.

A lexical closure can only form over variables in scope at that point.

let a = 1;
const foo = () => a;

a is in scope in the body of foo, but it is not a bound variable of the function foo -- it is a free variable.

A function with a free variable is an open expression, and can't be understood on its own.

To close the function, we capture (and share) the free variable, which binds it, and call the result a closure.

It also doesn't really make sense to talk about executing a function in a scope -- scope is a lexical property of the program, not a dynamic property of execution.

The point of producing a closed function is that it doesn't execute in a scope -- it has all of the things it requires bound already, so it just executes in the global environment like any other function.

 

You could pass foo to any other function and it would still return 1, even when a goes out of scope; how is that not a closure?

 

Even when a goes out of the scope of what? :)