Closures in Javascript
November 8, 2019 Leave a comment
Wherever the function is declared and defined, it remembers the complete snapshot of the function, i.e, the scope chains used within the function.
var a = 10; function outer() { var b = 20; var inner = function() { console.log(a); console.log(b); } return inner; } var innerFn = outer(); innerFn(); var innerFn1 = outer(); innerFn1();
When innerFn() is executed, it prints both ‘a’ and ‘b’. Printing ‘a’ is fine because its in global scope but printing ‘b’ looks interesting because var ‘b’ is in outer scope which is run and complete and hence no longer exists and there scope for var ‘b’ should not exists. But its working because JS has feature of CLOSURES.
In above program, global variables are created only once, whereas function variables are created as many times as the function is invoked.
So when innerFn() is invoked first time, it remembers snapshot of global var ‘a’ (created only once) and function var ‘b’ (created with outer function execution first time)
So when innerFn() is invoked next time, it remembers snapshot of global var ‘a’ (as before) and function var ‘b’ (created again with outer function execution second time)
To verify this make a small modification
var a = 10; function outer() { var b = 20; var inner = function() { a++; b++; console.log(a); console.log(b); } return inner; } var innerFn = outer(); innerFn(); var innerFn1 = outer(); innerFn1(); Output: 11 21 12 21
Asynchronous callbacks as closures
As JS engine is single threaded, there is no concept of pause/wait in the program. To achieve this we use a global function called ‘setTimeout’ where it fires the given function asynchronously after the specified time.
var a = 10; var fn = function() { console.log(a); } setTimeout(fn, 1000); console.log("done");
Important thing to notice here is that, this is the best example of CLOSUREs, because the function we declared is trying to access global variable ‘a’ which is remembered by the function eventhough its executed inside another function ‘setTimeout’
The Module Pattern in JS
var person = { "firstName": "Niranjan", "lastName": "Tallapalli", "getFirstName": function() { return this.firstName; }, "getLastName": function() { return this.lastName; } } person.getFirstName(); // would give me first name BUT person.firstName; // would also let me access the first name because there is no concept of private in JS
There is no concept of private variables in JS, everything is by default public. To make variable private, we can do one of the following
- We can make use of closures
- We can make use of Module Pattern
The idea here is to make use of the concept of new function SCOPE so that the variables are not visible outside the scope.
function createPerson() { var firstName = "Niranjan", var lastName = "Tallapalli", var person = { "getFirstName": function() { return this.firstName; }, "getLastName": function() { return this.lastName; } } } person.getFirstName(); // would give me first name as usual person.firstName; // will not work
Closures in Async Callbacks
var i; var print = function() { console.log(i); } for(i = 0; i < 10; i++) { //print(); setTimeout(print, 1000); }
‘print()’ will work fine and prints 0-9
setTimeout will print 10 ten times, its because by the time setTimeout runs 10 different instances of the function, the value of ‘i’ is changed to 10 and then exited the loop.
Now HOW do we solve this problem???
var i; for(i = 0; i < 10; i++) { (function() { // IIFE var currentValueOfI = i; setTimeout(function() { // make an inline function console.log(currentValueOfI); }, 1000); })(); } // OR var i; for(i = 0; i < 10; i++) { (function(currentValueOfI) { // IIFE setTimeout(function() { // make an inline function console.log(currentValueOfI); }, 1000); })(i); }
Recent Comments