JavaScript Closure Tutorial – How Closures and Lexical Scope Work in JS

freeCodeCampfreeCodeCamp
3 min read

By Dave Gray

In JavaScript, people often confuse closures with lexical scope.

Lexical scope is an important part of closures, but it is not a closure by itself.

Closures are an advanced concept that is also a frequent topic of technical interviews.

You should have a foundational understanding of functions before attempting to understand closures.

After reading this article, I hope I will have helped you learn the following:

  • The difference between lexical scope and closures.
  • Why closures require lexical scope.
  • How to give an example of a closure during the interview process.

What is Lexical Scope in JavaScript?

Lexical scope describes how nested (also known as "child") functions have access to variables defined in parent scopes.

const myFunction = () => {
     let myValue = 2;
     console.log(myValue);

     const childFunction = () => {
          console.log(myValue += 1);
     }

     childFunction();
}

myFunction();

In this example, childFunction has access to the variable myValue which is defined in the parent scope of myFunction.

The lexical scope of childFunction allows access to the parent scope.

What is a Closure in JavaScript?

w3Schools.com offers a great definition of what a closure is:

A closure is a function having access to the parent scope, even after the parent function has closed.

Let's note the first part of the sentence before the comma:

...a function having access to the parent scope

That's describing lexical scope!

But we need the second part of the definition to give an example of a closure...

...even after the parent function has closed.

Let's look at an example of a closure:

const myFunction = () => {
     let myValue = 2;
     console.log(myValue);

     const childFunction = () => {
          console.log(myValue += 1);
     }

     return childFunction;
}

const result = myFunction();
console.log(result);
result();
result();
result();

Copy the example code above and try it out.

Let's break down what is happening...

In this revision, myFunction returns childFunction instead of calling it.

Therefore, when result is set equal to myFunction(), the console statement inside myFunction is logged, but not the statement inside childFunction.

childFunction is not called into action.

Instead, it is returned and held in result.

In addition, we need to realize that myFunction has closed after it was called.

The line with console.log(result) should show in the console that result now holds the anonymous function value that was childFunction.

Now, when we call result(), we are calling the anonymous function that was assigned to childFunction.

As a child of myFunction, this anonymous function has access to the myValue variable inside myFunction even after it has closed!

The closure we created now allows us to continue to increase the value of the myValue variable every time we call result().

Take Your Time with Closures

Closures are considered to be an advanced concept for good reason.

Even with a step-by-step breakdown of what a closure is, this concept can take time to understand.

Don't rush your understanding and don't be hard on yourself if it doesn't make sense at first.

When you fully understand closure, you may feel like Neo when he sees the Matrix. You'll see new code possibilities and realize they were there all along!

I'll leave you with a tutorial on closures from my YouTube channel. I dive a little deeper and provide a few more examples of closures to build on the discussion in this article.

0
Subscribe to my newsletter

Read articles from freeCodeCamp directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

freeCodeCamp
freeCodeCamp

Learn to code. Build projects. Earn certifications—All for free.