JavaScript Fundamentals: Closures

In this article, we’re going to learn about a concept that’s fundamental in JavaScript development today: Closures. We’re going to understand how Closures work under the hood, why this concept is so popular among developers, and how we can benefit from using it in our code.

If you’ve been using JavaScript in your projects or in your company for a while, you might have heard about Closures. A lot of developers like this concept, but it seems like Closures are still a mystery. Sometimes developers might even be using it daily in their code and don’t know it yet! The problem with Closures is they seem like a mystery between developers — sometimes a developer might even know more or less how a Closure works but not know exactly how to explain it.

The best way I’ve found to learn or study something is to read everything related to a topic and practice implementing it, and then try to explain it to another developer. I have found that often it seems simple to explain a concept to another developer because I know how it works myself, but finding the right words to explain it to another person is far more complicated.

That’s why we’re going to dive deep in this article and learn everything we can about Closures, and then write some cases where we can see the benefits. After that, you’ll be able to explain in a simple sentence what Closures in JavaScript are and how they work. So, let’s get started!

A Little Bit about Scope

In JavaScript, to understand about Closures, we first need to understand a little bit about Scope and how it works.

Every time you declare a new function in JavaScript, that means you’re creating a new function scope. For example, let’s imagine that we’re going to create the following function:

function sayMyAge(yearOfBirth: number) {
      const year = 2019;
      const myAge = year - yearOfBirth;
      return `Your age is: ${myAge}`;
    };

As you can see, the sayMyAge function is simply making a calculation and returning the age of a specific person. Inside that function, we have a variable called year which is the current year, and the myAge variable which is our age calculated.

Since this function has its own scope, and as we know, in JavaScript all the variables and functions that we have inside a function will belong to that function, if we try to call it outside of our function, we’re going to receive an error.

console.log(year); // ReferenceError
    console.log(myAge); // ReferenceError

What exactly does this error tell us? Well, it tells us that these specific variables are not available to the global scope, and that’s why we’re receiving this error. We’re trying to return something that’s not available on the global scope, only in a function scope, in our case, the sayMyAge function scope.

One of the benefits of using a function scope to hide variables and functions is that you can avoid collision between variable names and also functions. If you have a collision between values in your code, that means you can have unexpected overwriting of values.

Now that we know a little bit about Scope in JavaScript, let’s learn more about Closures and how they work.

Understanding Closures

To understand exactly how a Closure works, we’re going to use our sayMyAge function and make some changes. First, we’re going to create a new function inside our sayMyAge function, and this function is going to be called logAge .

We’re going to move a part of our function inside that new logAge function, and the year variable that we had before, we’re going to maintain inside the inner scope of sayMyAge . So, our sayMyAge function is going to look like this:

function sayMyAge(yearOfBirth: number) {
      const year = 2019;

    function logAge(yearOfBirth) {
        const myAge = year - yearOfBirth;
        return `Your age is: ${myAge}`;
      }

    return logAge;
    };

As you can see, we moved our year variable to the inner scope of the sayMyAge function. Then, we created a new function called logAge , which is going to return our age, based on a calculation made using the year variable, and the yearOfBirth which is our function parameter.

Now, on our global scope, we’re going to create a new variable called age, and assign to this variable our sayMyAge function, like this:

const age = sayMyAge;

If we try to console this age variable, we’re going to receive our sayMyAge function value, since we’re not invoking it.

const age = sayMyAge;

    console.log(age);

    // Result:
    //

So now, let’s make a quick change and see what happens. First, let’s redeclare the age variable; instead, this time, we’re going to invoke the sayMyAge function. Also, when we console the age variable, we’re going to invoke it this time and pass a year to it. Let’s see what happens.

const age = sayMyAge();

    console.log(age(1997));

    // Result:
    // Your age is: 22

We just created a Closure! You might not know exactly what happened here and how we ended up creating a Closure, so let’s go to it and understand what happened step by step:

  1. We created our sayMyAge function, with a year variable inside of its inner scope. Also, inside of its inner scope, we created a function called logAge , which uses the year variable to calculate our age.
  2. The logAge function uses its parent scope, which is the sayMyAge scope, and gets the year variable from there. Inside our sayMyAge function, we’re returning just the logAge function.
  3. When we assign the sayMyAge function to the age variable, we have lost the inner scope of sayMyAge . That means that, in theory, we shouldn’t have access to the year variable. But in JavaScript, our inner functions still reference values created inside the scope , in our case the sayMyAge scope.
  4. Then, when we invoke the age and pass an argument to it, it executes the logAge function, referencing and using the year variable that once was declared inside the sayMyAge scope.

Basically, a Closure is a function inside another function, that has access to its parent scope, and is exposed to the global scope. What does this mean? It means that this function will be used in another part of the code, making the variables inside of it private.

Pretty neat, a not-so-simple concept to catch at first, but when you do realize what’s going on under the hood, you start to admire the beauty of JavaScript!

Another Example

Let’s create another example to understand Closures even better. We’re going to create a function called favoriteMovie , which is going to return the favorite movie of an individual.

Our favoriteMovie function is going to be similar to the last one that we created, so this time, if you didn’t yet catch on to the magic about Closures, hopefully you can have your a-ha! moment.

Our favoriteMovie function is going to look like this:

function favoriteMovie(name: string) {
      function myFavoriteMovie(movie: string) {
        return `Hi ${name}, your favorite movie is ${movie}!`;
      }

      return myFavoriteMovie;
    }

As you can see, our favoriteMovie function receives a name as an argument, and returns a function called myFavoriteMovie . This function is receiving a movie as an argument, and returning a string with the name and movie passed. In the other function that we created, we had a variable declared inside the parent scope — in that case, the sayMyAge function. In this case now, we’re not going to have any variable declared.

Now, let’s create a variable called user and pass to it the favoriteMovie , passing a name to it.

const user = favoriteMovie("Leonardo");

Now that we passed a name to our function, we’re going to invoke the user function and pass our movie, like this:

console.log(user("Pulp Fiction"));

    // Result:
    // Hi Leonardo, your favorite movie is Pulp Fiction!

The only way that you can master Closures and understand it deeply is by practicing! So, start to create a lot of functions, and try to build something complex and apply this concept in code. See how it’ll lead you to write code that’s more concise, clearer and simpler.

Closures in JavaScript are pretty neat. They’re not so simple a concept at first glance, but as you learn what’s going on behind the scenes, the elegance of JavaScript really shines!

Conclusion

In this article, we learned about scope in JavaScript at first, and then we learned about Closures in JavaScript — how they work, and how we’ve been using them all over our code for a long time and didn’t know it. Closures are also an important concept to master for the interview process, so if you’re hoping to get a new job offer soon, it’s a very good concept to master and understand. Plus, you’re going to use them all over your code, and after you master them, it’ll get easier to code and create awesome things.

我来评几句
登录后评论

已发表评论数()

相关站点

热门文章