What are Closures?

This is probably the hardest question of all these questions because Closures is a controversial topic. So I'm gonna explain it from what I understand.

Closures is simply the ability of a function at the time of declaration to remember the references of variables and parameters on its current scope, on its parent function scope, on its parent's parent function scope until it reaches the global scope with the help of Scope Chain. Basically it is the Scope created when the function was declared.

Examples are a great way to explain closures.

   //Global's Scope
   var globalVar = "abc";

   function a(){
   //testClosures's Scope
     console.log(globalVar);
   }

   a(); //logs "abc" 
   /* Scope Chain
      Inside a function perspective

      a's scope -> global's scope  
   */ 

In this example, when we declare the a function the Global Scope is part of a's closure.

a's closure

The reason for the variable globalVar which does not have a value in the image because of the reason that the value of that variable can change based on where and when we invoke the a function.
But in our example above the globalVar variable will have the value of abc.

Ok, let's have a complex example.

var globalVar = "global";
var outerVar = "outer"

function outerFunc(outerParam) {
  function innerFunc(innerParam) {
    console.log(globalVar, outerParam, innerParam);
  }
  return innerFunc;
}

const x = outerFunc(outerVar);
outerVar = "outer-2";
globalVar = "guess"
x("inner");

Complex
This will print "guess outer inner". The explanation for this is that when we invoke the outerFunc function and assigned the returned value the innerFunc function to the variable x, the outerParam will have a value of outer even though we assign a new value outer-2 to the outerVar variable because
the reassignment happened after the invocation of the outer function and in that time when we invoke the outerFunc function it's look up the value of outerVar in the Scope Chain, the outerVar will have a value of "outer". Now, when we invoke the x variable which have a reference to the innerFunc, the
innerParam will have a value of inner because thats the value we pass in the invocation and the globalVar variable will have a value of guess because before the invocation of the x variable we assign a new value to the globalVar and at the time of invocation x the value of globalVar in the_Scope Chain_ is
guess.

We have an example that demonstrates a problem of not understanding closure correctly.

const arrFuncs = [];
for(var i = 0; i < 5; i++){
  arrFuncs.push(function (){
    return i;
  });
}
console.log(i); // i is 5

for (let i = 0; i < arrFuncs.length; i++) {
  console.log(arrFuncs[i]()); // all logs "5"
}

This code is not working as we expected because of Closures.
The var keyword makes a global variable and when we push a function
we return the global variable i. So when we call one of those functions in that array after the loop it logs 5 because we get
the current value of i which is 5 and we can access it because it's a global variable. Because Closures keeps the references of that variable not its values at the time of it's creation. We can solve this using IIFES or changing the var keyword to let for block-scoping.