JavaScript Closures in Plain Language
and one practical real-world example
What are JavaScript closures?
It is a JavaScript feature that allows a function to access its outer function scope. Sounds complicated?
We can use this feature when we have nested functions like this:
As you can see the function sayAge
has access to the variable age
which is in the outer function scope. This is a special feature of JavaScript and we can use it in some situations that I will explain.
A common trick with closures
If we return a function from another one we can mutate the outer function variables by using the closure feature. For example:
JavaScript closures are as simple as this example but I didn’t understand them till I found a practical usage.
Implementing private variables by using JavaScript Closures
We can use this feature to implement private methods inside a JavaScript function:
As we can see setAge
has access to privateAge
and it can alter this variable. We returned three methods: increment
, decrement
and value
and the user cannot assign something directly to privateAge
.
Practical real-world example
I used a few things in this example but please do not get too bogged down. This example is a simple typescript express app that is going to connect to a database(MongoDB) and execute a query.
If you want to use this example on your local machine follow these steps:
- You need a MongoDB server(The default port is set to 27022 in this project).
- Run these commands:
git clone https://github.com/pshaddel/js-closure-example.git
cd js-closure-example
npm install
npm run dev
We have two routes: one for testing /ping
which returns pong
in response and the other one is users
.
In this example, I didn’t use any service or controller for simplicity. Let’s see what is inside the users.ts
and connection.ts
:
On every get
request to /users
we want to execute a find
query in the MongoDB database. Now a common problem is that we don’t want to create a new connection on each request. What we want is to use one instance of connection and there are two ways(at least I know two ways :)). one of them is using Singleton pattern and classes in typescript and the other one is JavaScript Closure.
Now let’s look at the implementation of connection which returns a function named getDBClient
:
getDBClient
is the function inside this file which has access to the outer function scope. So getDBClient
has access to databaseClient
variable. Look at line 9: if the databaseClient
variable is not null we are going to return the client
instance and otherwise, we’re going to create a new client. We used closure to mutate an outer function variable.
Now no matter how many times we call this API, the code will not create a new connection to the database.
Use this command to send request if you are using Linux or Mac OS:
curl http://localhost:3000/users
As we can see the first time we created a connection to the database: Connected — Client Created
and after that each time we needed a connection the code returned the previous instance of database client and logs: using previous instance
(connection.ts).