back to all posts

YDKJS — Scopes and Closures — Part5

by Nabendu Biswas / June 13th, 2018

#javascript #beginners #webdev
Series: YDKJS

Welcome to the Part5 of YDKJS series. As told in part1 this series is based on my learnings from legendary book series You don’t know JS by Kyle Simpson and Javascript series by Kaushik Kothagal from Javabrains.

We will start one of the most complex topic of Javascript here ie Closures. But one think to know is that Closures are everywhere in JS.

Let consider a simple example without closure, which we will refactor to use closure later.

Simple inner outer exampleSimple inner outer example

The above is a simple example of an inner() inside an outer(). The inner() is both declared and executed from inside the outer function.

Now, since in JS functions are first class citizen. We can have the function inner executed from anywhere else also. We will refactor the above to do so using function expressions.

Refactoring inner outer exampleRefactoring inner outer example

So, we changed inner to a function expression and returned it. So, when we call outer, we can save the return value to a variable innerFn.

Let’s understand one thing. The variable b have an scope in outer function ie from line 4 to line 10. So, at line 13 when we call the outer function, it can access the value of b, but at line 14 there is no outer function.

So, how does the innerFn() access the value of b. This is where the JS feature of Closures comes into play. When the var inner is created at line 6, the JS engine not only stores the function object information but also it’s scope information. So, it stores a scope of variable a and b inside the inner function object. Now it doesn’t matter where you call inner, whether in this file or some third party file. It will always remember the value of a and b, as if a snapshot is been taken.

It is to be noticed that the snapshot is a pointer to these variables and not a copy. So, if you change variable a and b here, it will be changed in function inner.

One thing to also know is if we call outer 2 times then how many copies of a and b gets created.

Copies of a and bCopies of a and b

As seen above to added line in inner to increment a and b variables. Now since a is global variable it’s value is 11 first time and 12 the second time then innerFn2 is called.

But b have an snapshot in the inner function, so each new call through a new innerFn will start b at 20 and print it as 21 because of the increment.

Let’s now see a practical example of closure. Javascript is single threaded, so if we want our problem to wait we use the setTimeout function provided by JS.

closures in actionclosures in action

Here the setTimeout at line 7, is calling a function fn. This fn is a function expression console log the variable a. Now when this fn is created it gets the snapshot of var a and even if the setTimeout is called from another file which have no concept of var a, this variable gets prints after a delay of 6 seconds.

Now, let’s consider another practical use of closures. We have the concept of getters and setter in OO languages like Java. By this we hide the variables from outside world in a function/class and make them private. They can only be access via getter methods and set via setter methods.

Will try to create them in Javascript. Consider our first try below.

First try for gettersFirst try for getters

Here we created a person object and have two properties of firstName and lastName holding the value. And then two getters getFirstName and getLastname to get those values. As we can see in the console, we are able to do a person.getFirstName() but we are also able to do a person.firstName We should not be able to do this, but we don’t have a concept of private variables in Javascript like in Java.

So, we will refactor our code to use the concept of closures to achieve the same. Consider the below code.

getters in Javascriptgetters in Javascript

We first put the object in a function createPerson. Then we move the var firstName and lastName outside the object. We have the usual getFirstName and getLastname inside the object. We then return the object.

Now at line 16, we call the function and then assign the return value ie the object in a variable person. The person variable can access the getFirstName but not the firstName. It is because firstName scope is from line 2 to line 13 and not accessible outside it.

But the person.getFirstName() is a closure executed. When the getFirstName was created at line 6, it got the snapshot of the variable firstName because of the concept of closure. This is how person.getFirstName( ) is able to access the value of firstName.

This concludes our You Don’t know JS — Scopes and Closures series. Will see you soon in the Object and Prototype series.

Nabendu Biswas