cft

All you need to know about Closures — The first pillar of Javascript.

We are able to create closures in Javascript because functions are a first-class citizen and we have Lexical scope.


user

Allan Sendagi

2 years ago | 8 min read

This article is inspired by my Andrei’s course https://www.udemy.com/course/advanced-javascript-concepts/

Closures and prototypes are the two pillars of Javascript which when understood properly gives you superpowers.

Closures in Javascript are possible because of two things:

  1. Functions are first-class citizens. We can pass functions around like data — like any other type in Javascript.
  2. Lexical scope: Based on where our code is written, the Javascript engine knows before we even run the code what variables each function has access to.

And that's what closures are — a combination of a function and the lexical environment from which it was declared.

Closures allow a function to access variables from an enclosing scope or environment even after it leaves the scope in which it was declared.

Closures allow a function to access variables from an enclosing scope or environment even after it leaves the scope in which it was declared.

function a and function b are higher-order functions because they return functions. function c is a normal function because we are just returning a piece of string. Let's run this code and see what happens.

function a returns function b

function b returns function c

function c gives us grandpa, father, and son.

The question then becomes: How did function c remember what grandpa was? Because if we remember how the Javascript engine runs code —

we know that function a got run and then popped off the stack. And when things get popped off the stack, we remove the variable environment and things are garbage collected.

But here that is not the case; somehow son has access to grandpa and father even after we called function b!

So what just happened here? Well, closures happened.

With closures, when a function runs, it gets pushed onto the stack; we create a variable environment and the context execution has grandpa as a variable. It would also have parameters such as the arguments keyword but because we haven't given it any other parameters, there are no other variables.

Once we call a(), it gets removed from the stack. It's gone but grandpa still remains. That's because grandpa goes into the closure box.

This closure box is technically where the memory heap is — it’s a bunch of memory and as soon as we don't need things anymore, it gets removed.

However, when the garbage collector comes, sees grandpa, it says there is closure here, it’s in the special closure box. This closure box I can’t clean up because there is something that is referencing grandpa from inside of it.

So the next b function gets called, again we add it to the stack. A new variable environment is created and we have father as our variable. Once we remove father, or once b gets popped off the stack, once again father is being referenced by another function inside of it so it gets put into the closure box.

And then c comes around, gets called and we have c in the variable environment. When we return the statement, grandfatherfatherson, the variable environment is going to return and say, let's find out what the grandpa variable is. It's going to look in the variable environment and it's going to say — no I can't find it.

Now instead of looking in the global scope, or the global variable, it looks in the closure box. And says hey do you have grandpa and father? And indeed it will find it there.

The Javascript engine will make sure that the function has access to all the variables outside of the function with this closure. So closure is a feature of Javascript.

And this is something unique. The Javascript engine will make sure that the function has access to all the variables outside of the function with this closure. So closure is a feature of Javascript.

From the function above, function c is inside of function a and function b. The Javascript engine is going to create a closure and all the variables outside of the c function, it's going to keep around as long as c is using them.

Suppose we had another variable random. Here once b is invoked, it won't keep random around — it’s going to get garbage collected because nothing is referencing it. But it will keep anything that is being referenced by the child function. So, in this case, still needs father and grandpa so it's going to keep it around.

Closures are also called lexical scoping. Lexical meaning where it was written and scoping meaning what variables it has access to.

Closures are also called lexical scoping. Lexical meaning where it was written and scoping meaning what variables it has access to.

So by that definition, the Javascript engine before it runs any code, before anything, it already knows which functions have access to which variables.

Javascript is lexically scoped or statically scoped. During the first phase, it looks through the code and says hey I am going to keep grandpa and father around even if they get called because I am going to create these scope chains. This is why we can use closures.

We can have functions that return functions and we have this idea of lexical scope meaning where we write the function matters not where we call the function.

Let's have another example.

Or we can use arrow functions:

Now if I run this function

This is one reason closures are powerful. Imagine if we have:

And let's wait five years. Then do:

We could hypothetically wait 5 years if the Javascript engine is running and then finally call booString even though the boo() function is off the stack.

It will still remember that this is what we gave it five years ago. That's because parameters are treated just like local variables that get stored in variable environments.
We can wait five years and hold on to information in memory, doesn't get deleted and I can call it whenever I want.

Let's look at another example.

After 3 seconds, we get a callback

We have used closures to be able to do this. The function with setTimeout gets sent to the web API to start a timer for 3 seconds. Once the timer is done, we send the function to the callback queue and the callback queue is going to wait there until the call stack is empty.

So, callMeMaybe has been called and it's now popped off the stack. Now the event loop is going to push this setTimeout function onto the stack and run it and console.log(call me).

Notice variable callMe should be gone. callMeMaybe has been popped off the stack by the time our function runs. But because of closures, even if the function goes out to the API world, it can still use closures.

But because of closures, even if the function goes out to the API world, it can still use closures.

We are able to remember this variable because of closures.
Now based on what we know about closures, suppose we remove the variable 
callMe from up there and move it down. What's going to happen?

It still works because it doesn't matter where we define this variable. Even if it’s a const that doesn't get hoisted, we don't care about hosting here. Instead, our function goes into the web API world, gets put on the callback queue, the event loop pushes it back onto the stack. By that time we’ve already created and assigned const callMe. And since there is an enclosing function that is using it, it's going to create a closure.

Closures can be very memory efficient and allow us to do Encapsulation.

Closures and Memory

Closures have two main benefits:

  1. They can be very memory efficient.
  2. They allow us to do Encapsulation.

These are the coolest part of closures.

So how are closures memory efficient?
We can start off with a function:

Now let's assume this is a heavy-duty operation that we need to do; let's assume we are accessing this massive array — indices.

I am accessing index 700 of bigArray.

Now let's assume our index 700 is in a database and gets accessed a lot — so that we call this function many times.

Every time we are creating bigArray and destroying it

We see here that we are creating bigArray , adding data to our memory — which memory is limited, and we are creating the function every time. We are adding this to memory every time and we return it, and because nothing is referencing it, it gets destroyed. Every time!

That doesn't look very efficient. Wouldn’t it be great if we could create bigArray once? Since we know it’s going to be used a lot, it’s created once and we just have it in memory so that we can just access it instead of doing all that work.

How can we do that with closures?

Well, let's create a new function with closures.

We have a reference to bigArray in our returned function hence we have created a closure

function with closures gets created only once

We can see the difference here. The first heavyDuty was created four times vs heavyDuty2 where we were able to create bigArray only once. Because we knew we were gonna access it a lot, we just maintained that closure scope over it and we were able to call it over and over without doing all that creation — destruction work.

Encapsulation

Here we used closures. The timeWithoutDestruction is something that all these functions have access to. But we also wouldn't want people to have powers to launch. So let's remove the launch function from the returned object and instead just have totalPeaceTime.

So that if try to launch, I get an error

This is what encapsulation does. It's hiding information that is unnecessary to be seen by the outside world or information that can be manipulated.

This gets into the idea of the principle of least privilege — a big security principle when it comes to programming. Here you don’t want to give anybody access to your API, your special functions, or variables.

By using closures we are able to access things like timeWithoutDestruction that I don’t want anybody accessing because I just want setInterval to constantly increment that. But at the same time, I still want people to access things like totalPeaceTime so that that totalPeaceTime can access the variables that are sacred to me. And this is one of the main benefits of closures — data encapsulation. It refers to the idea that some data shouldn't directly be exposed.

Modules in Javascript especially classical module patterns that people used to use with IIF, use this pattern and we are only able to do that because of closures.

Let's look at another example.

How can the function below be called only once so that we can avoid someone abusing it and run it a bunch of times? We want our function to run only once, no matter how many times its called.

Our display is set thrice. We would prefer to have it set once

So how can we fix this using what we know about closures?

Now it doesn’t matter how many times I call my function, it will only run once.

Let's look at another example

This has to be one of the most common interview questions for Javascript developers and there are two ways of solving this problem.

Now if I run this function I will get I am at index 4 logged 4 times.

The easiest way is to change the var keyword to let because let allows us to use block scoping.

let allows us to use block scoping unlike var

With let, the curly brackets create scope for each i. Note that initially with vari was part of the global scope. We didn’t have a function surrounding it. So that when the setTimeout finally returned, the for loop had already gone through everything and turned i into 4.

But what if we couldn't use the Let keyword?

We can use closures to wrap setTimeout into an immediately invoked function.

Here as long as we reference in the function, because of closures it won't be removed from the local scope.

We do that by passing this immediately invoked function parameter i ; So that with parameter i every time it loops, we will be incrementing 0,1,2…

We receive the in our function as closureI(Just to keep the name separate)and we can access it with the array as well as array[closureI]

To summarise,
we have seen an important pillar of Javascript — closures. We have learned that a closure is the combination of a function and a lexical environment in which it was declared.

We are able to create closures in Javascript because functions are a first-class citizen and we have Lexical scope.

Therefore the statement we made earlier that, “Closures allow a function to access variables from an enclosing scope or outer scope environment even after it leaves the scope environment in which it was declared” makes sense. Because as we have seen, all that matters in Javascript is where the function was written.

Upvote


user
Created by

Allan Sendagi

Technology will save homo sapiens from extinction


people
Post

Upvote

Downvote

Comment

Bookmark

Share


Related Articles