Before deep diving into closures. Let’s understand few concepts.
Avoid Global Variables
Using of Global variables should be avoided as much as we can. Let’s understand this with help of an example.
Here we expect that script1 and script2 should be printed.
Which means there should be 2 file variables. Let’s check that out.
File variable just have 1 value of script2. As in Javascript the previous value is overridden therefore it is prefer to avoid using global variables as variable are in global scope.
Let’s implement a setTimeout to be sure if variable are getting overridden.
IIFE
So as to avoid the above problem we can define the variables in the function scope.
This solution works but the problem still exist as we can’t use the same function name in both the files as the function are in global execution context/space.
So as to resolve this issue, we can use IIFE where we can remove the function name and are used for one time use.
The most easiest way of solving the above problem was by using Let as it provides a block level scope to the variables.
{
let file = "script2";
console.log(file);
}
file variable is not bound to the global execution context now.
Closures
Let’s jump into example and understand this.
What do you think should be the output of the function ? 10 20 and 20 30
Now let’s make some modifications in the code.
Now what do you think should be the answer. Here outer function is returning the inner function. We know about the execution contexts. Once the execution context of the outer function is completed, the javascript file should not have access to its data member. In clear words, if we call the inner function now, j variable should not be accessible as execution context of the outer function is completed. Let’s check that out.
We see that we get the same output. But How ?
This is because of the concept called closures where inner function has access to the scope of the outer function in the lexical scoping. And the inner function can be called in the global scope.
Let’s play around with closures and understand closures in a more better way.
What will be the output ?
It would be 20 30 and 20 30. Because once the inner function is called and its execution is finished, it is popped out of the execution context and called again later from scratch.
Question 2
What will be the output now ?
The output will be 20 30 and 21 30, because the execution context of the inner has been popped out but the reference with the outer function remains the same as outer function is not called again. Therefore the j is incremented.
Question 3
Some Questions on let
Bindings in Arrow Functions
There are few differences in normal functions and arrow functions. A normal function has its own binding to this keyword, arguments or super. Normal function has its own binding to this depending on how the function is called, weather it is called from a global context => then this refers to global, if its called via object, then this refers to the object and so on.
However, in case of Arrow function they do not have their own binding to this. They look up in the outer scope for the value of this. Let’s understand this with help of an example:
Let’s see the difference in case of ES6
Question
The function which is getting returned i.e. return function(){ console.log(`The full name of the user is ${this.firstname} ${this.lastname} `); } Is a unbounded function (An unbound function is a function that is not bound to an object) So this in the above function refers to the global (window) object. Since unbound functions are implicitly bound to the global scope). And since no firstname and lastname variables were defined in the window environment, ${this.firstname} ${this.lastname} prints undefined undefined.