# Closures and It's Properties

Closures allow a method to access variables of another method, even though the method left the stack. Closures are the combination of `function` and `lexical scope`.

To see closures in actions,

```js
// A simple closures example
function hoc() {
  // "willBePreserved" is a closure
  const willBePreserved = "Screaming Eagle Cabernet Sauvignon";
  return function child() {
    console.log(willBePreserved);
  };
}

const returnedMethod = hoc();
returnedMethod();
```

Here, the `hoc` method has the property `willBePreserved`. This `willBePreserved` belongs to `hoc` and also used in the `child` method. When we are done calling the `hoc` method, the garbage collector came and remove the `hoc` from the calling stack. But, since the `child` method use the `willBePreserved`, it will be preserved. This `willBePreserved` is the closures.

## Properties

A couple of properties of closures are,

- Closures can be used with the event loop
- Closures will not preserve a variable that is not referenced
- Closures ignore the rules of hoisting

### Closures can be used with the event loop

Let's see the closures in action with the event loop,

```js
// An example of using Closures with WEB API
function closuresWithEventLoop () {
  const preservedVal = 'I am preserved!';
  setTimeout(() => {
    console.log(preservedVal); // display "I am preserved!"
  }, 5000);
}
```

Here the `setTimeout` will go to the web API to be executed. In the meantime the garbage collector will remove the `closuresWithEventLoop` method but will keep the `preservedVal`. After a delay of 5 seconds the `preservedVal` will be printed in the console.

### Closures will not preserve a variable that is not referenced

Closures only preserve a variable from the garbage collector that is referenced.

```js
// An example of using closures with WEB API
function closuresWithLocalVariable () {
  /**
  * Since not referenced in the returned method,
  * the "notPreservedVal" will be removed from garbage collector
  */
  const notPreservedVal = 'I am not preserved!';
  
  /**
  * Will be preserved from the garbage collector,
  * as it is used in the returned method
  */
  const preservedVal = 'I am preserved!';
  
  return function() {
     console.log(preservedVal); // display "I am preserved!"
  }
}

const returnedMethod = closuresWithLocalVariable();
returnedMethod(); // display "I am preserved!"
```

In this example, since the `notPreservedVal` is not referenced anywhere, it will not be preserved.

### Closures ignore the Hoisting rule

JavaScript does not hoist the `const` or `let`. Hoisting is only available when declare a variable with `var` keyword. In the following example, we can see, even if the variable is declared with `const`, it will be displayed and printed.

```js
// Example of closures ignores hoisting
function closuresHoising() {
  setTimeout(function() {
    console.log(willBePreserved);
  }, 1000);
  // "const" never hoisted, but here we can print it in "setTimeout" method
  const willBePreserved = "I am hoisted even declared with 'const'";
}

closuresHoising(); // Display "I am hoisted even declared with 'const'"
```

## Interesting use case with Closures

With closures, we can come up with a couple of interesting coding use case,

- Memory optimization
- Memory encapsulation
- Interesting pattern

### Memory optimization

Let's consider a method, that returns the history of a country. To do so, it first load all the country, their history and keep them in a hashmap. Then according to the country name, it returns the history of the specific country.

```js
// Use to fetch country list and their history
// Then return the history of a country passed as param
function getCountryHistory (countryName) {
  // Fetch all the country list from a public api
  // Sort them locally
  // Fetch history for each country
  // Load country history in a hashMap { [key: countryName]: countryHistory
  const countryHistory = {
    country_name_1: 'country_1_history',
    country_name_2: 'country_2_history',
    country_name_3: 'country_3_history',
  };
  
  return countryHistory[countryName];
}

getCountryHistory('country_name_1'); // Display 'country_1_history'
```

You might notice, every time we call the method `getCountryHistory`, it fetches all the data, store them in memory and return the result. With closures, we can optimize the solution, so only once the data will be fetched. Every time we call the method, the result will be showed from the closures. Let's see the optimized solution in action,

```js
// optimize solution
// Use to fetch country list and their history
// Store them in a hashMap as closures
function loadCountryHistory () {
  // Fetch all the country list from a public api
  // Sort them locally
  // Fetch history for each country
  // Load country history in a hashMap { [key: countryName]: countryHistory
  const countryHistory = {
    country_name_1: 'country_1_history',
    country_name_2: 'country_2_history',
    country_name_3: 'country_3_history',
  };
  
  return function(countryName) {
     console.log(countryHistory[countryName]); 
  }
}

// this loads the country history in closures
const getCountryHistory = loadCountryHistory(); 

getCountryHistory('country_name_1'); // Display 'country_1_history'
getCountryHistory('country_name_2'); // Display 'country_2_history'
```

### Interesting Pattern

Lets consider a function `initialize()` and it set some global value. The important thing is it should be called only one time.

```js
let globalKey;

function initialize() {
  globalKey = "value";
  console.log("Global key is set");
}

initialize();
initialize();
initialize();
```

Here the function is being invoked 3 times. With closure, we need to call it once.

```js
let globalKey;

function initialize() {
  let isCalled = false;
  return () => {
    if (isCalled) {
      return;
    }
    isCalled = true;
    globalKey = "value";
    console.log("Global key is set");
  };
}

const startOnce = initialize();
startOnce();
startOnce();
startOnce();
```

Now, this will be only called once.

Another approach to solve the problem can be, updating the function reference after being initialize at the first time.

```js
let globalKey;

function initialize() {
  globalKey = "value";
  console.log("Global key is set");
  initialize = () => {
    console.log("Aboarting! already set the value");
  };
}

initialize();
initialize();
```

Using IIFE, we can do some improvement,

```js
let globalKey;

const initialize = (() => {
  let called = 0;
  return () => {
    if (called) {
      console.log("Already Set");
      return;
    }
    called = 1;
    globalKey = "Global Value";
    console.log("Set the value");
  };
})();

initialize();
initialize();
initialize();
```

We will see the output of

```
Set the value
Already Set
Already Set
```

### Another Interesting Pattern [Bonus]

Let's consider following snippet,

```js
const array = [1, 2, 3, 4];

function traverse() {
  for (var i = 0; i < array.length; i++) {
    setTimeout(function () {
      console.log(i);
    }, 1000);
  }
}

traverse();
```

The output will be,

```
4 4 4 4
```

In this case, the var has used the hoisting and got the latest index. using `let` instead of `var` can resolve the issue.

```js
const array = [1, 2, 3, 4];

function traverse() {
  for (let i = 0; i < array.length; i++) {
    setTimeout(function () {
      console.log(i);
    }, 1000);
  }
}

traverse();
```

Since we are in the world of closures, let's solve it using IIFE and closures,

```js
const array = [1, 2, 3, 4];

function traverse() {
  for (var i = 0; i < array.length; i++) {
    (function (val) {
      setTimeout(function () {
        console.log(val);
      }, 1000);
    })(i);
  }
}

traverse();
```

Our desired output now,

```
0 1 2 3
```

## Q/A

- https://dmitripavlutin.com/javascript-closures-interview-questions/
- https://betterprogramming.pub/10-javascript-closure-challenges-explained-with-diagrams-c964110805e7

## Final Thoughts


Closures are very interesting concepts and powerful tools. Please let me know if your thoughts/usage of closures in daily programming.

References: [JavaScript: The Advanced Concepts](https://www.udemy.com/course/advanced-javascript-concepts/) by [Andrei Neagoie](https://www.udemy.com/user/andrei-neagoie/)

