blog thumnail

What is Closures in JavaScript?

javascript

Tanveer Sayem / 2022-11-17

7 min read

Closures are so confusing at first because they are an 'invisible' concept. However, after reading this article you will understand 'all' about Closures in JS.
When you are writing code oftentimes you need a variable and you create one. You use that variable in an object or in a function. You don't really think much about it. But you might have used closures, you just didn't realize it.
So learning closures is less about understanding a new concept and more about recognizing something you have already been doing for a while.

TL:DR

You have a closure when a function accecess varaibles defined outside of it. In JavaScript, closures are created every time a function is created, at function creation time.
For example, this code snippet contains a closure:
const users = ['Rahim', 'Shafique', 'Rafique'];
let name = 'Rafique';
const user = users.filter(user => user.startsWith(name));
Notice how user => user.startsWith(name) is itself a function. It uses the name variable. But name is defined outside of the function. This is closure.

Function have access to outside variables

We have to undestand how function and variables work in JavaScript to understand what closure is. Let's take the below greeting function, where we declare variable name inside it and then print it out.
function greeting() {
     let name = 'Rahim';
     console.log(`Hello! ${name}`);
}
greeting(); // Logs 'Hello! Rahim'
But what if we want our variable to be easily changable. So, we can actually do that by simply moving the name variable outside of the greeting function.
let name = "Rahim"; 
function greeting() {
 console.log(`Hello! ${name}`)
}
This lets us change the name variable anytime from the outside of the function.
greeting(); // Logs 'Hello! Rahim'
name = 'Shafique';
greeting(); // Logs 'Hello! Shafique';
name = 'Rafique';
greeting(): // Logs 'Hello! Rafique';
In other words, the name variable is no longer local to our greeting function, but our greeting function still have acces to the outer variable. Function have access to outside variables. Stop for a seccond and make sure you have no problem with this idea. Once this makes sense mode onto the next section.

Nesting another code in a function call

Let's say we have some code:
/* A snippet of code */
It does not matter what the above does, but let's assume we want to run it twice. One way to do it would be to copy and paste it:
/* A snippet of code */
/* A snippet of code */
Another way to do it would be to use a loop:
for(let i = 0; i < 2; i++) {
   /* A snippet of code */
}
The third way which we're particularly intereseted in today, is to nest it in a function:
function doIt() {
   /* A snippet of code */
}
doIt();
doIt();
Using a function gived us the ultimate flexibility because we can run this function any number of times, at any time - and from anywhere in our program. We can also call our new function only once if wanted to.
function doIt() {
   /* A snippet of code */
}
doIt();
Notice how the above code is equivalent to the original code snippet:
/* A snippet of code */
In other words, if we take some piece of code, “nest” that code in a function, and then call that function exactly once, we haven’t changed what that code is doing. There are some exceptions to this rule which we will ignore, but generally speaking this should make sense. Sit on this idea until your brain feels comfortable with it.
If you click on my affiliates links and shop(anything, not just books), I am going to receive a tiny commission. AND… Most of the time, you will receive an offer. Win/Win! The products that I have are the ones I believe in.
amazon

Discovering Closures

We have traced our way through two different ideas:
  • Function have access to outside variables
  • Nesting code in a function and calling it once does not change the result
Now let’s see what happens if we combine them.
We’ll take our code example from the first step:
let name = "Rahim"; 
function greeting() {
 console.log(`Hello! ${name}`)
}
greeting();
We will nest this whole example into a function, which we're going to call once:
function startADay() {
 let name = "Rahim";
 function greeting() {
  console.log(`Hello! ${name}`)
 }
}
startADay();
Read both snippets one more time and make sure that they are equivalent.
This code works! But look closer. Notice the greeting function is inside the startADay function. Is that even allowed? Can we really put a function inside another function?
There are languages in which a code structured this way is not valid. For example, this code is not valid in the C language (which doesn’t have closures). This means that in C, our second conclusion isn’t true — we can’t just take some arbitrary piece of code and wrap it in a function. But JavaScript doesn’t suffer from that limitation.
Let’s go through the above code together — step by step. First, we declare the startADay function at the top level. We immediately call it. It has a name local variable. It also contains an greeting function. Then it calls that greeting function. Because greeting is inside of startADay, it “sees” all of its variables. This is why it can read the name variable.
This is called a closure.
Let's go back to the function that we introduced in the TL:DR section:
const users = ['Rahim', 'Shafique', 'Rafique'];
let name = 'Rafique';
const user = users.filter(user => user.startsWith(name));
It may be easier to notice the closure if we rewrite it with a function expression:
const users = ['Rahim', 'Shafique', 'Rafique'];
let name = 'Rafique';
const user = users.filter(function(user) {
 return user.startWith(name);
})
Whenever a function accesses a variable that is declared outside of it, we say it is a closure. The term itself is used a bit loosely. Some people will refer to the nested function itself as “the closure” in this example. Others might refer to the technique of accessing the outside variables as the closure. Practically, it doesn’t matter.

A Ghost of a Function Call

Closures might seem deceptively simple now. This doesn’t mean they’re without their own pitfalls. The fact that a function may read and write variables outside has rather deep consequences if you really think about it. For example, this means that these variables will “survive” for as long as the nested function may be called:
function startADay() {
   let name = 'Rahim';
   function greeting() {
    console.log(`Hello! ${name}`);
   }
   setTimeout(greeting, 5000);
}
startADay();
Here, name is a local varaible inside the startADay() function call. It's tempting to think it "disappears" after we exit startADay, and it won't come back to haunt us.
However, inside of startADay we tell the browser to call greeting in five seconds. And greeting reads the name variable. So the JavaScript engine needs to keep the name variable from that particular startADay() call available until greeting has been called. In that sense, we can think of closures as of “ghosts” or “memories” of the past function calls. Even though our startADay() function call has long finished, its variables must continue to exist for as long as the nested greeting function may still be called. Luckily, JavaScript does that for us, so we don’t need to think about it.

Why "Closures"?

Finally, you might be wondering why closures are called that way. The reason is mostly historical. A person familiar with the computer science jargon might say that an expression like user => user.startsWith(name) has an “open binding”. In other words, it is clear from it what the user is (a parameter), but it is not clear what name is in isolation. When we say “actually, name refers to the variable declared outside”, we are “closing” that open binding. In other words, we get a closure.
Not all languages implement closures. For example, in some languages like C, it is not allowed to nest functions at all. As a result, a function may only access its own local variables or global variables, but there is never a situation in which it can access a parent function’s local variables. Naturally, that limitation is painful.
There are also languages like Rust that implement closures, but have a separate syntax for closures and regular functions. So if you want to read a variable from outside a function, you would have to opt into that in Rust. This is because under the hood, closures may require the engine to keep the outer variables (called “the environment”) around even after the function call. This overhead is acceptable in JavaScript, but it can be a performance concern for the very low-level languages.
And with that, I hope you can get a closure on the concept of closures!
Read more: Closures | MDN
If you click on my affiliates links and shop(anything, not just books), I am going to receive a tiny commission. AND… Most of the time, you will receive an offer. Win/Win! The products that I have are the ones I believe in.

Subscribe to the newsletter

Get emails from me about web development, tech, and early access to new articles.


  • Home
  • About
  • Newsletter
  • Twitter
  • Github
  • YouTube
  • Setup
  • Guestbook
  • Snippets