JS Closures

A few years back during a work seminar, I had the opportunity to dive into JS waters and see a bit of its beauty. Up to that point my background was C, C++, Java a bit NodeJS, but I never had the luck to see how functional programming really looks like. For those two months I was mind blown (in a good and bad way see JS ‘==’ ) since I had discovered a completely new way of programming. Among the things I really enjoyed was closures. So what closures really are?

According to wiki:

In computer science, a closure is a function that has an environment of its own. Inside this environment, there is at least one bound variable. Closures were first used in programming languages such as ML and Lisp. When a closure is used more than once, the bound variables stay the same in between

Before we understand what that means lets talk about functions’ lexical scope and global scope. Whatever is enclosed within brackets will be called inner scope and outside the brackets outer scope. Outer scope can extend multiple times in cases of nested functions and until we reach the global scope where everything lives in. For every function call we make, a new inner lexical scope is created with its own variables and its hidden [[Environment]] property (which cannot be accessed) points to the outer scope. Too much to digest so lets start coding!

Lexical Scope

Here we have the variable sport declare on the global scope. In this case the [[Environment]] property is null since there is no outer’er’ scope in global scope.

let sport = "basketball";
console.log(sport);

In the following case function play is called on line 5 and variable sport is passed as an argument. Variable sport now belongs to the lexical/inner scope of function play. [[Environment]] property of play function now points to the global/outer scope and contains the function name and sport variable.

1. let sport = "basketball";
2. function play(sport){
3.  console.log("I love "+ sport)
4. }
5. play(sport);
---------------------------------
prints:"I love basketball"

Now, assuming that we omit the function’s variable this will happen. First, the play function will check its inner scope and will try to find a variable named sport. If a value is not found then it will reach the outer scope and will keep doing so till it reaches the global scope which is one step distance in our case.

let sport = "basketball";

function play(){
  console.log("I love "+ sport)
}
play();
---------------------------------
prints:"I love basketball"

So, we have played with function lets go and see a for loop. Variable ‘i’ is declared within the for loop scope and thus can not be accessed from outside with console.log() line 5. The internal log will work just fine though!

1. for (let i = 0; i < 10; i++) {
2.   console.log(i);
3. }
4.
5. console.log(i);

Declaring i outside the for loop is a decent workaround

let i = 0
for (i; i < 10; i++) {
  console.log(i);
}

console.log(i);

Now that we have seen the basics of scopes, lets move forward to JS inception aka closures!

Closures

Having in mind what a lexical scope is, lets move forward with closures!

Our first closure will be something like this:

let ball = function () {
  let ballType = "basketball";

   let type = function () {
    return console.log(ballType);
  };
  return type;
}

let foo = ball();
foo();
---------------------------------
prints:"basketball"

In the example above we pass control from ball function to type function but please notice that the variable is still accessible. When foo was declared, it created a reference to the inner function type of ball. In other words ball is part of the outer scope of type where ballType is declared and has access to.

Now that we masted beginner’s level lets swift gears with the example below. Take a closer look before reading the solution.

1. let walk = 0,run =0;
2.
3. let cardio = function(){
4.  let walkTempo = walk++;
5.  let runTempo = run++;
6.  let heartRate = 80
7.
8.  var treadmill =  function(){
9.       var pulse = heartRate++;
10.      console.log(walkTempo + '  ' + runTempo + '  ' + pulse);
11.  }
12.  return treadmill;
13. }
14. let legday1 = cardio();
15. let legday2 = cardio();
16. let legday3 = cardio();
17.
18. legday1();
19. legday1();
20. legday2();
21. legday1();
22. legday3();
---------------------------------
prints:
"0  0  80"
"0  0  81"
"1  1  80"
"0  0  82"
"2  2  80"

This is how the story goes:

in lines 14..16 we create cardio functions with each one having its own [[Environment]] property. On line 18, we call legday1. Initially, walk and run variables have value zero, heart rate 80 and don’t forget, ++ operator applies after the assignment. When we reach the inner function we expect logger to print 0 0 80. At that point something has happened. HeartRate within treadmill has increased by one and has affected its outer scope meaning that on next iteration, pulse will print 81. How about the other two values? If you guessed that they will stay the same you are right! Treadmill affected only the heartRate variable but the global scope of walk and run was affected. So, on line 20 we expect to see that both walk and run tempo have value 1, but as for pulse, a new lexical scope was created with legday2 so we expect to see the default value. The same logic applies for lines 21 and 22. Mind blown ha?

Loops and Closures

So far we have discussed about loops and their value scope, we mastered closures, so why not mix those two? I mean… what could possibly go wrong?

Here we have a palette of colors and we want to filter and store those whose name starts with letter B. Take a look and think what the result will be

var paletteArray = new Array("Green","Black","Blue","Brown","Yellow","Pink");
var colorsStartWithB = {};
var j =0;

for(var i = 0;i<paletteArray.length;i++){

  if(paletteArray[i].startsWith("B")){   
      colorsStartWithB[j++] =  function (){
        return console.log("My favorite color is: "+ paletteArray[i] +" with number: "+i);    
      };    
  }
}
for (var i = 0; i < j; i++) {
    colorsStartWithB[i]();             
}
---------------------------------
prints:
    "My favorite color is: undefined with number: 6"
    "My favorite color is: undefined with number: 6"
    "My favorite color is: undefined with number: 6"

So, if we wrote java we would get a glorious ArrayIndexOutOfBoundsException, so cute! How did that happen? Well we depended on outer scope variable i which does 6 for iterations (array length) plus 1 (++) iterations. How can we solve that problem? There are multiple approaches:

1) Create a function responsible for filtering the colors. How will this help us? When we pass an argument to a function it creates a local variable which lives within function’s scope.

2) Assign paletteArray[i] to a const or let type of variable. The reason is that in each for loop, separate memory allocation takes place and so the value is not affected.

Lets start with first case, we extracted the console.log to a function with i being its parameter.

var paletteArray = new Array("Green","Black","Blue","Brown","Yellow","Pink");
var colorsStartWithB = {};
var j =0;

for(var i = 0;i<paletteArray.length;i++){

  if(paletteArray[i].startsWith("B")){     
      colorsStartWithB[j++] =  favoriteColor(i);
  }
}

  function favoriteColor(i){
        return function(){console.log("My favorite color is: "+ paletteArray[i] +" with number: "+i); };   
      };    

for (var i = 0; i < j; i++) {
    colorsStartWithB[i]();             
}
---------------------------------
prints:
"My favorite color is: Black with number: 1"
"My favorite color is: Blue with number:  2"
"My favorite color is: Brown with number: 3"

Solution number 2 looks like this:

var paletteArray = new Array("Green","Black","Blue","Brown","Yellow","Pink");
var colorsStartWithB = {};
var j =0;

for(var i = 0;i<paletteArray.length;i++){
const color = paletteArray[i];
let position = i;  

  if(color.startsWith("B")){   
     colorsStartWithB[j++] = function (){
        return console.log("My favorite color is: "+ color +" with number: "+i);    
      };    

  }
}
for (var i = 0; i < j; i++) {
    colorsStartWithB[i]();             
}
---------------------------------
prints:
"My favorite color is: Black with number: 1"
"My favorite color is: Blue with number:  2"
"My favorite color is: Brown with number: 3"

In the example above can you guess what the output would be if we made color of type var? The output would look like this:

prints:
"My favorite color is: Pink with number: 1"
"My favorite color is: Pink with number: 2"
"My favorite color is: Pink with number: 3"

JS is a total mess but a fun mess nevertheless!

Closures and private methods

I guess most people here are familiar with object oriented programming and java in particular. Here we will see how the private method concept can be applied in JS, even though it doesn’t have any native support. Lets look at the example below:

let throttle = (function() {
  let speed = 0;
  function changeBy(val) {
    speed += val;
  }
  return {
    accelerate: function() {
      changeBy(1);
    },
    decelerate: function() {
      changeBy(-1);
    },
    value: function() {
      return speed+"Km/h";
    }
  };
})();

console.log(throttle.value());
throttle.accelerate();
throttle.accelerate();
console.log(throttle.value());
throttle.decelerate();
console.log(throttle.value());
---------------------------------
prints:
"0Km/h"
"2Km/h"
"1Km/h"All

As you can see we don’t have direct access to speed but we can apply all the necessary functions to change and retrieve its value. All three functions share the same lexical scope and thus can affect its value.

If you want to dive a bit more into this subject a good place to start is mozilla developers page and this awesome book Secrets of the JavaScript Ninja.