JavaScript Closures with examples
Published: 2023-09-30 07:03:18


In JavaScript, _Closure_ is a phenomena of a code getting executed outside its lexical scope. They happen because of writing lexically structured code.

In other words, Closures let us access a foreign parent scope even after it has exited the runtime. Closures are created every-time we create a scope. They are strongly associated with scopes so before exploring Closures, let us refresh what lexical scopes are.


### Lexical Scope

You might be already familiar with the concept of Scope and Execution contexts in JavaScript. If you would like a refresher on these topic, consider a recent article I wrote, similar to this: [Mastering JavaScript Scopes](https://dev.to/odus_ex/advanced-javascript-mastering-scopes-and-related-concepts-5787)

Let's cover the important highlights here briefly. 

JavaScript associates important execution details of a program with the place they are declared in the source code, pertaining to the visibility of declared entities. At author time, these are called _Scopes_. At runtime these become _Execution Contexts_ and are called on _Execution Stack_ one after another to hold the information required for successful execution of the code.

Consider the following example:

```js

function greet(name, typeOfGreeting){

let nameInUpper = name.toUpperCase();

function sayHello(){
 const greetings = `Hello ${nameInUpper} :)`
 return greetings;
}

function sayHi(){
 const greetings = `Hi ${nameInUpper}!` 
 return greetings;
}

return typeOfGreeting === 'hi' ? sayHi : sayHello;
}

```
In the above example, `greet` function creates a functional scope. This scope contains two other functions, `sayHello` and `sayHi` along with `greet` arguments and variable `nameInUpper`.

Note that nested scope can access declared entities of the enclosing scope. This means both `sayHello` and `sayHi` can access entities of `greet` (and Global Scope).

However, a parent scope cannot access entities declared in its nested scopes. So `greet` doesn't have access to entities declared inside `sayHi` and `sayHello`.

Also, note that two `greetings` variables are created without conflict because they are in separate scopes, i.e. one in `sayHi` and one in `sayHello`.



### Closures in action

Now that we understand scopes, lets explore how closures "happen" as a result of writing lexically scoped code.

When we execute `greet` like below:

```js

const greetBen = greet("ben", "hi");

console.log(greetBen()) // Hi BEN!

```
We notice a rather peculiar behaviour. On executing `greetBen` we are able to remember entities declared in `greet` and use them at later point of time in code (i.e. in `console.log()`), even when `greet` has completed its execution well before executing `greetBen`.

This is Closures! `greetBen` is said to have formed a closure on `greet`. This allows `greetBen` to keep the entities declared in `greet` "alive" (i.e. stop being garbage collected), even after its execution context has been popped out of execution call stack.

For better understanding, consider a slightly modified example below:

```js
const greetBen = greet("ben", "hi");

setTimeOut(() => console.log(greetBen()), 5000)
```

The above code prints the same output as before but after 5 seconds, re-enforcing our understanding of keeping the entities alive and dynamically accessing a them at runtime even when the scope in which they were declared is not available.


### Closure Examples

Now that we have seen some basic examples, let us discuss a couple of advanced ones.

Consider the following code:

```js
(function iife1(a) {
  return (function iife2(b) {
    console.log(a); // What is logged?
  })(1);
})(100);
```

After a good look, we recognise that `iife2` forms a closure with `iife1` and hence has access to `a`. The output of the program will be 100.


Consider another code-snippet:

```js
for (var i = 0; i < 3; i++) {
  setTimeout(function print() {
    console.log(i); // What is logged?
  }, 1000);
}
```

Because `var` declarations do not create block scopes, the closure formed by `print` on the enclosing scope (i.e. Global Scope) will get the final updated value of `i`. Hence the above code will print `3`, `3`, `3`.

If we were to replace `var` with `let`, then the enclosing scope for `print` will be `for` block instead of the Global Scope, as `let` creates a block scope. On each loop iteration, a new scope will be created and the updated `i` value will be generated for each new scope, resulting in sustaining each value as the loop iterates. Hence the output would then be `0`, `1` and `2`.

I have borrowed these examples from an amazing blog by _Dimitri Palvutin_. You can find more of such examples by visiting his write-up [here](https://dmitripavlutin.com/javascript-closures-interview-questions/).



### Design Patterns 

JavaScript developers have been utilising Closures to create some of the most famous design patterns in the language. Some of them are discussed below:

**Functions as first class citizens**

We are able to pass around functions in JavaScript due to closures. A function as argument forms the closure with the calling function.

```js

function doMath(value, operation){
  return operation(value)
}

function addFive(number){
  return number + 5;
}

function multiplyFive(number){
  return number * 5;
}

console.log(doMath(5, addFive)); // 10

console.log(doMath(5, multiplyFive)); // 25

```

Here, `operation` function is able to form a closure with `doMath` enabling us to operate on `doMath` argument. It is using this behaviour, we are able to implement callbacks and event-listeners in the language.


**Module Pattern**

Closures are utilised to create data encapsulation and data abstraction. Consider the example below:

```js 
function CounterModule(){

// Data Encapsulation
let counter = 0;

function reset(){
 counter = 0
}

function increment(){
 counter++;
}

function decrement(){
 counter--;
}

function getCounter(){
  return counter;
}

return {
  reset,
  increment,
  decrement,
  getCounter
}

}


// Data Abstraction
let {reset, increment, decrement, getCounter} = CounterModule();

}
```

In the example above, we created a `CounterModule` with a private implementation detail `counter`. We then define operations allowed to be performed on this private data by using functions like `reset`, `increment` and `decrement` because these function form closure with `CounterModule`.

Thats all what Closures are!

I hope that this article helped you understand Closures and how it is utilised in everyday JavaScript code to implement some of the most important language behaviours and characteristics. 

Until next time. Happy Hacking! :)