Understanding Closures in Javascript
Tags: javascript, functional, programming
Published: 2021-02-17 10:46:26

The closure is one of the most important and elegant concepts of JS. It forms the most fundamental concept of many important functions and concepts in JS. It is a powerful concept that allows us to create many useful and powerful pro-level functions like `once` and `memoize`.

Many JavaScript `design patterns` including the `module pattern` use closure. Moreover, Closure allows us to `build iterators`, handle the `partial application`, and `maintain state` in an asynchronous world.

Before understanding and getting in-depth into the closure please keep in mind that whenever a function runs or invoked then it gets a new execution context with local memory. When a function gets called then the function is pushed onto the call stack. When the function starts executing we create a live store of data that can be called `local memory`, `variable environment`, or `state`. When the function finishes executing, the result is returned and execution context with its local memory is deleted and the function is popped off the call stack.

But with closures, we can create functions with memories. The closure is just a function that returns another function. The following is an example of closures.

```js
function createFunction() {
 function multiplyBy2 (num){
    return num*2;
 }
 return multiplyBy2;
}
const generatedFunc = createFunction();
const result = generatedFunc(3);
```

Now, look at the following function without actually running it in the console. Go through the function theoretically and try to predict the result keeping in mind our current understanding and discussion so far.

```js
function outer () {
  let counter = 0;
  function incrementCounter () { 
    counter++; 
  }
  return incrementCounter;
}
const myNewFunction = outer();
myNewFunction();
myNewFunction();
```

The execution will take as follows:

1. First of all we are declaring a function named `outer`.
2. Now we are declaring a const `myNewFunction` which is uninitialized.
3. Then we are calling the `outer` function and it is put on the call stack. Now it will create a new execution context with the local variable environment.
4. Inside the `outer` function, first, we declare a variable counter to 0. And we are defining a function `incrementCounter` and lastly returning the function `incrementCounter`. Now the outer is popped off the calls stack and its execution context gets deleted.
5. Now the const `myNewFunction` gets initialized with the returned value of the `outer` i.e function definition of `incrementCounter`. Now the `myNewFunction` will be like.
`function myNewFunction (){ counter ++; }`
6. Now we are calling `myNewFunction`. It will be added to the call stack.
7. This will create a brand new execution context and Local environment variable.
8. In the function definition, we can see the counter is incremented but the counter variable is not declared or initialized.

Now theoretically this should result in an `error` the counter is not declared or initialized.

Now try to run it in the console, you will notice that it will not result in an error but something strange happens. The result will be:- `1` and `2`

> **Lexical scope:** One intricacy of JavaScript is how it looks for variables. If it can’t find a variable in its local execution context, it will look for it in its `calling context`. And if it doesn't found there, it will keep looking, until it reaches the `global execution context`. And if it does not find it there, it’s undefined.

**But how this can be possible ?**

The Answer is..... **THE BACKPACK**.

## The Back Pack

The concept of the backpack was introduced to me by Will Sentance while I was going through Javascript the hard parts course. No doubt one of the best online courses taught by certainly the best instructor I ever had with excellent teaching skills.

Now let us go back to the previous code and at the instance when the `incrementCounter` is returned to the const `myNewFunction` (Line Number: 5).  Whats happens at that stage is that `myNewFunction` somehow maintains the bond to `outer` function local memory i.e, the local memory of the `outer` function gets ***returned out*** and attached on the back of `incrementCounter’s` function definition. So `outer’s` local memory is now stored and attached to `myNewFunction` - even though the `outer’s` execution context is long gone.  When we run `myNewFunction` globally, it will first look in its own local memory (as we’d expect), but then in `myNewFunction’s` **backpack.**

What makes them so special that the function return will have a special hidden `[[scope]]` property attached with it which can be called a backpack for better understanding. That contains a reference to all the variables in the local memory of the main function that returned that function. And this way we can have a function that has access to the local memory of the main function even after it has been executed i.e even after its execution context is deleted. The closure gives our functions persistent memory.

The different name of the backpack

1. Closed over ‘Variable Environment’ (C.O.V.E.)
2. Persistent Lexical Scope Referenced Data (P.L.S.R.D.)
3. Backpack
4. Closure - Official

```js
function outer () {
 let counter = 0;
 function incrementCounter () {
   counter ++;
 }
 return incrementCounter;
}

const myNewFunction = outer();
myNewFunction(); // 1
myNewFunction(); // 2

const anotherFunction = outer();
anotherFunction(); // 1
anotherFunction(); // 2
```

We call the `outer()` function and store the returned value with the backpack in const `myNewFunction`. The `myNewFunction` will have access to all the `[[scope]]` property containing the live data of `outer` in the backpack or closure. Now the myNewFunction will have a definition of `incrementCounter` and will be something like:

```js
function myNewFunction () {
  counter ++;
 }
```

As soon as we call `myNewFunction` for the first time, a brand new execution context is created and put on top of the call stack. Now it will look for the counter variable in its **local environment**, and it will not find it there. And then it will look for it in the **backpack** and will find it there will the value of 0. And then increment it and return it and the function is popped off the call stack.  

Now we are again calling `myNewFunction` and now again brand new execution context is created and put on top of the call stack. Now again it will find the counter in the **backpack** and not in the local memory.

But this time the value of the counter is 1 as set by the previous `myNewFunction` call as the backpack is still the same as we are instance of `outer()` is the same. It will increment it to 2 and return it and the function is popped off the call stack.

If we run `outer` again and store the returned `incrementCounter` function definition in `anotherFunction`, this new `incrementCounter` function was created in a new execution context and therefore has a brand **new independent backpack**.

Every instance of the `outer` function being executed create a brand new backpack or closure.

## Uses of Closures

- Gives our functions persistent memory.
- Helper functions: Everyday professional helper functions like ‘once’ and ‘memoize’
- Iterators and generators: Which use lexical scoping and closure to achieve the
most contemporary patterns for handling data in JavaScript
- Module pattern: Preserve state for the life of an application without polluting the
global namespace
- Asynchronous JavaScript: Callbacks and Promises rely on the closure to persist state
in an asynchronous environment

That's all! If you have any suggestions or find any errors in the article please let me know in the comment section. If you enjoyed the article please share it on social media platforms.