JavaScript Closure In Action

Who is this article intended for?

 
All folks who are working with JavaScript, learning JavaScript, or have been using fancy JavaScript frameworks and platforms like AngularJS, NodeJS or even as basic as jQuery or if you plan to start writing JavaScript and transitioning from object-oriented languages like C# or you are a reader and like reading non-fiction articles.
 

JavaScript

 
JavaScript is the most forgiving language I have ever come across. Everything just seems to work, well this can be dangerous, sometimes - if not always; we might end up writing something that works but may be very inefficient or even worst, after a long day’s work, the script might seem perfect but the output may be equally bizarre. I agree that JavaScript may be unintuitive, occasionally, even counterintuitive. Let’s look at the following example to see what I mean.
 
JavaScript 
  1. 'use strict'  
  2. for(var i = 0; i < 10; i++) {  
  3.     console.log('"i" is equal to ' + i);  
  4. }  
  5. //Code 1.0 
Can you guess what output will it produce? You guessed it right.
 
It will produce the following output, 
  1. "i" is equal to 0   
  2. "i" is equal to 1   
  3. "i" is equal to 2   
  4. "i" is equal to 3   
  5. "i" is equal to 4   
  6. "i" is equal to 5   
  7. "i" is equal to 6   
  8. "i" is equal to 7   
  9. "i" is equal to 8   
  10. "i" is equal to 9    
  11.   
  12. //Output 1.0  
Pretty predictable right? Now, let's add a tiny bit of complexity, we want to add a delay between the output prints. Meaning, we want to print 0 instantly, 1 after 1 sec, 2 after 2 sec and so on and so forth. This isn’t much of a challenge, right? Following your intuitions you might write something similar.
 
JavaScript
  1. 'use strict'  
  2. for(var i = 0; i < 10; i++) {  
  3.     setTimeout(function() {  
  4.         console.log('"i" is equal to ' + i + ' (after ' + i + ' secs)');  
  5.     }, (1000 * i));  
  6. }  
  7. //Code 1.1 
And you would be expecting following output, 
  1. "i" is equal to 0 (after 0 secs)   
  2. "i" is equal to 1 (after 1 secs)   
  3. "i" is equal to 2 (after 2 secs)   
  4. "i" is equal to 3 (after 3 secs)   
  5. "i" is equal to 4 (after 4 secs)   
  6. "i" is equal to 5 (after 5 secs)   
  7. "i" is equal to 6 (after 6 secs)   
  8. "i" is equal to 7 (after 7 secs)   
  9. "i" is equal to 8 (after 8 secs)   
  10. "i" is equal to 9 (after 9 secs)    
  11.   
  12. //Assumed Output 1.1  
If you thought so, I won’t blame you.
 
Above code will actually produce following output.
 
Bizarre right? Didn’t I say that javascript can be counterintuitive sometimes!
 
What just happened? – Well, Meet Closure!
 
What you just encountered is called closure. Well, Don’t be rude, say hello! Closure is a friend if understood and used wisely but a fearful enemy if left unnoticed.
 
Closure enables functions to remember its scope of execution. Meaning, it makes functions remember the variables and other functions it refers to. Closure makes the referred variables and functions available, even after the scope is exited, latest values are reflected. The simplest example of closure is following hello world example,
 
JavaScript
  1. 'use strict'  
  2. //Following function returns a function which prints - Hello `name`!     
  3. function sayHelloTo(name) {  
  4.     return function() {  
  5.         //This function "remembers" the name -- thanks to closure.    
  6.         console.log('Hello ' + name + '!');  
  7.     }  
  8. }  
  9. var helloWorld = sayHelloTo('World');  
  10. /*    The closure enables the child function "remember" the "name" variable    even after the parent scope has exited. */  
  11. //Prints out "Hello World!" in the console.     
  12. helloWorld();  
  13. //Code 1.2 
produces
  1. Hello World!  //output 1.2   
Pretty neat right? And this is what happened with our first example, closure. A little bit cryptic, ain’t it? Let me elaborate, javascript runs on a single thread, so it queues up tasks that need differed execution, remember setTimeout - we used it in our first example? So what happened with the example is first the for loop executes and iterates for 10 times with value of i = 0 to 9, with each iteration it executes setTimeout block with appropriate value of i, meaning for i = 0 => setTimeout(<function>,0) for i = 1 => setTimeout(<function>,1000) and for i = 9 => setTimeout(<function>,9000).
 
Now setTimeout is executed but the <function> goes through deferred execution, so the first <function> is executed only after the for loop is executed completely. So at the time when <function> executes, the for loop has already exited, and the final value is equal to 10. Now due to closure, <function> remembers the I and fetches the latest value, which is 10 and hence the cryptic output. What we learned is that the value of i is NOT COPIED for each iteration instead the reference is remembered.
 
How do I make it work then?
 
There is more than one way to get what we want. First let's look at IIFE.
 
Option 1: IIFE
 
IIFE (immediately-invoked function expression) are function expressions that are executed as soon as they are defined. For example
 
JavaScript 
  1. 'use strict'  
  2. //The IIFE     
  3. (function(arguments) {  
  4.     /* Awesomeness goes here */  
  5. })();  
  6. //Code 1.3 
As you can see that the function is invoked as soon as it is defined. So we can rewrite Code 1.1 as,
 
JavaScript
  1. 'use strict'  
  2. for(var i = 0; i < 10; i++) {  
  3.     /*      IIFE with a parameter i, this i parameter is different then i in  
  4.                the for loop. IIFE forces a new execution scope to be created  
  5.                and current *value* of the i in for loop is *copied* to the new  
  6.                scope     
  7.       */  
  8.     (function(i) {  
  9.         //i has *value* i (of for loop) at the time of invocation         
  10.         setTimeout(function() {  
  11.             console.log('"i" is equal to ' + i + ' (after ' + i + ' secs)');  
  12.         }, (1000 * i));  
  13.     })(i); //i of the for loop is passed as parameter, forcing new scope to be       
  14.     //created with current copy of i.     
  15. }  
  16. //Code 1.1.1 

Option 2: Function.prototype.bind

The above example with IIFE looks quite complex and mouthful. As we now have an idea on how to solve the problem on hand, all we need to do is force create new scope and Function.prototype.bind can be used to do so.
 
JavaScript 
  1. 'use strict'  
  2. for(var i = 0; i < 10; i++) {  
  3.     /*  
  4.           (<function(i)>).bind(this, i) forces a new scope to be created *copying*  
  5.           the current *value* of i  
  6.     */  
  7.     setTimeout((function(i) {  
  8.         console.log('"i" is equal to ' + i + ' (after ' + i + ' secs)');  
  9.     }).bind(this, i), (1000 * i));  
  10. }  
  11. // Code 1.1.2 
This version is very much similar to Code 1.1, only difference is instead of setTimeout(<function>,timeout) we have setTimeout( (<function(i)>).bind(this, i), timeout). So instead of asking setTimeout to defer <function> we are asking it to defer a copy of <function>bound to current value of i. 
 
Option 3: The ES6 way!
 
Let is almost exactly same as var except the fact that it creates lexically scoped variables. Variables created declared with let have limited to the scope they are defined in, in case of for loop, for each iteration, new copy of i is created which limits to that particular iteration.
 
JavaScript 
  1. 'use strict'  
  2. /*    We are using `let` instead of `var`, `let` creates a `lexically` scoped  
  3.       variable i, meaning, for each iteration of for loop a new copy of i is  
  4.       created, so closure captures the `lexically` scoped reference   
  5. */  
  6. for(let i = 0; i < 10; i++) {  
  7.     setTimeout(function() {  
  8.         console.log('"i" is equal to ' + i + ' (after ' + i + ' secs)');  
  9.     }, (1000 * i));  
  10. }  
  11. // Code 1.1.3 
All of these three options produce following output.
 
JavaScript
  1. "i"  
  2. is equal to 0(after 0 secs)  
  3. "i"  
  4. is equal to 1(after 1 secs)  
  5. "i"  
  6. is equal to 2(after 2 secs)  
  7. "i"  
  8. is equal to 3(after 3 secs)  
  9. "i"  
  10. is equal to 4(after 4 secs)  
  11. "i"  
  12. is equal to 5(after 5 secs)  
  13. "i"  
  14. is equal to 6(after 6 secs)  
  15. "i"  
  16. is equal to 7(after 7 secs)  
  17. "i"  
  18. is equal to 8(after 8 secs)  
  19. "i"  
  20. is equal to 9(after 9 secs)  
  21.     // Output for 1.1.1, 1.1.2, 1.1.3 

A word of Caution

As you can see, closures are powerful, but as uncle ben once said With great power comes great responsibility. Unnecessary usage of closure can make your code inefficient. Because every time a closure is created memory is consumed to store and maintain the references, sometimes this will result in a poor-quality program. So always make sure that you eliminate any unnecessary and unintended closures.
 
For example, one should not write functions inside functions and access parent functions values when there are better ways to do the same thing. Because doing so would create unnecessary closure. Take a look at the following example.
 
JavaScript 
  1. 'use strict'  
  2.   
  3. function Car(make, model) {  
  4.     return {  
  5.         setMake: function(value) {  
  6.             make = value;  
  7.         },  
  8.         getMake: function() {  
  9.             return this.make;  
  10.         },  
  11.         setModel: function(value) {  
  12.             model = value;  
  13.         },  
  14.         getModel: function() {  
  15.             return model;  
  16.         },  
  17.         print: function() {  
  18.             console.log(make, model);  
  19.         }  
  20.     }  
  21. }  
  22. var skodaSuperb = Car('Skoda''Superb');  
  23. skodaSuperb.print();  
  24. skodaSuperb.setModel('Octavia');  
  25. skodaSuperb.print();  
  26. // code 1.4 
Output
  1. Skoda Superb  
  2. Skoda Octavia  
  3. //output 1.4 
This code heavily uses closures, but does not need to, there are better ways to do it, for example look at the following example.
 
JavaScript 
  1. 'use strict'  
  2.   
  3. function Car(make, model) {  
  4.     this.make = make;  
  5.     this.model = model;  
  6.     this.setMake = function(make) {  
  7.         this.make = make;  
  8.     }  
  9.     this.getMake = function() {  
  10.         return this.make;  
  11.     }  
  12.     this.setModel = function(model) {  
  13.         this.model = model;  
  14.     }  
  15.     this.getModel = function() {  
  16.         return this.model;  
  17.     }  
  18.     this.print = function() {  
  19.         console.log(this.make, this.model);  
  20.     }  
  21. }  
  22. var skodaSuperb = new Car('Skoda''Superb');  
  23. skodaSuperb.print();  
  24. skodaSuperb.setModel('Octavia');  
  25. skodaSuperb.print();  
  26. // code 1.5 
Output
  1. Skoda Superb     
  2. Skoda Octavia      
  3.     
  4. //output 1.5  
Above code is written in the right direction and also looks fine, but if you take another look, you’d see that each function this.setMake, this.getMake, this.setModel, this.getModel and this.print creates a closure, which is clearly not required or used anywhere in the program. So it would be wise to remove them by following any of the two options

Option 1: Setting the prototype

It is wise to put the functions in the prototype, as shown below
 
JavaScript
  1. 'use strict'  
  2.   
  3. function Car(make, model) {  
  4.     this.make = make;  
  5.     this.model = model;  
  6. }  
  7. /* attach functions to the prototype */  
  8. Car.prototype.setMake = function(make) {  
  9.     this.make = make;  
  10. }  
  11. Car.prototype.getMake = function() {  
  12.     return this.make;  
  13. }  
  14. Car.prototype.setModel = function(model) {  
  15.     this.model = model;  
  16. }  
  17. Car.prototype.getModel = function() {  
  18.     return this.model;  
  19. }  
  20. Car.prototype.print = function() {  
  21.     console.log(this.make, this.model);  
  22. }  
  23. var skodaSuperb = new Car('Skoda''Superb');  
  24. skodaSuperb.print();  
  25. skodaSuperb.setModel('Octavia');  
  26. skodaSuperb.print();  
  27. //code 1.5 
output
  1. Skoda Superb     
  2. Skoda Octavia      
  3.     
  4. //output 1.5  
Above code is what should be written ideally. No Unnecessary closure are created and all’s well.
 
Option 2: Function.prototype.call (A cleaner way)
 
This method is very similar to option 1, actually we are writing option 1 is a more readable way.
 
JavaScript
  1. 'use strict'  
  2.   
  3. function Car(make, model) {  
  4.     this.make = make;  
  5.     this.model = model;  
  6. }  
  7. (function() {  
  8.     this.setMake = function(make) {  
  9.         this.make = make;  
  10.     }  
  11.     this.getMake = function() {  
  12.         return this.make;  
  13.     }  
  14.     this.setModel = function(model) {  
  15.         this.model = model;  
  16.     }  
  17.     this.getModel = function() {  
  18.         return this.model;  
  19.     }  
  20.     this.print = function() {  
  21.         console.log(this.make, this.model);  
  22.     }  
  23. }).call(Car.prototype);  
  24. //Passing Car.prototype as "this"     
  25. //using Function.prototype.call, attaching required functions     
  26. //to Car's prototype       
  27. var skodaSuperb = new Car('Skoda''Superb');  
  28. skodaSuperb.print();  
  29. skodaSuperb.setModel('Octavia');  
  30. skodaSuperb.print();  
  31. //code 1.6 
output
 
  1. Skoda Superb   
  2. Skoda Octavia    
  3.   
  4. //output 1.6  
or
 
Option 2.1 (Nonobject Oriented way)
 
function.prototype.call can be used differently (not like option 2’s Object-Oriented Way).
 
JavaScript
  1. 'use strict'  
  2.   
  3. function Car(make, model) {  
  4.     this.make = make;  
  5.     this.model = model;  
  6. }  
  7.   
  8. function setMake(make) {  
  9.     this.make = make;  
  10. }  
  11.   
  12. function getMake() {  
  13.     return this.make;  
  14. }  
  15.   
  16. function setModel(model) {  
  17.     this.model = model;  
  18. }  
  19.   
  20. function getModel() {  
  21.     return this.model;  
  22. }  
  23.   
  24. function print() {  
  25.     console.log(this.make, this.model);  
  26. }  
  27. var skodaSuperb = new Car('Skoda''Superb');  
  28. //this is set to skodaSuperb for print function     
  29. print.call(skodaSuperb);  
  30. //this is set to skodaSuperb for setModel function     
  31. setModel.call(skodaSuperb, 'Octavia');  
  32. print.call(skodaSuperb);  
  33. // code 1.6.1 
Output
  1. Skoda Superb   
  2. Skoda Octavia    
  3.   
  4. //output 1.6  
There are more ways to get the same thing done, and you’d be the judge of whats the best given the scenario.
 
What now?
 
This was my attempt to explain closure and how it affects almost every line of code that we write in javascript and how to take advantage of it and how to avoid it, how to create new execution scopes etc.
 
In coming articles we’ll take a look into functional programming with javascript, then on basic building blocks of functional programming - call, bind and apply along with very handy higher-order functions like map, reduce and filter.
 
I hope you guys enjoyed this article. Feel free to comment below, See you soon.
 
Read more articles on JavaScript


Similar Articles