Closures in JavaScript

Vladut, once our intern now a permanent member of our software engineering team, wanted to share his experience on closures in JavaScript in the hope that it would help other developers understand them better. This article is the first in a series dedicated to use cases of various programming problems, concepts, and methods.

Closures are powerful JavaScript tools that many developers tend to ignore. Understanding closures may seem difficult at first, but it’s all about the principles behind them.

Function properties

In JavaScript, just like any other programming language, a function can access any variable stated in its body.

function myFunction() {
         var foo = 1;
         return foo * 2;
 }

The result after calling the function is “2”.

In the function detailed above, the lifespan of the foo variable is the same as the execution time of myFunction(). The value of the foo variable is “1” at the start of every function call and can only be used in the function body.

Functions can access not only the variables inside their body, but also global variables:

var bar = 2;
function myFunction() {
         var foo = 1;
         return foo * bar;
}

The result returned by the function is once again “2”.

In the function above, the lifespan of the foo variable is limited by the execution time of myFunction(), whereas the lifespan of the bar variable is the same as the lifespan of the window.

Although you can set your own preferences, the use of global variables is generally considered to be a disadvantage because they can be modified at any time by any other function, and this can compromise the good functioning of the application.

Helpful concepts

The concept of lexical scoping refers to the way in which certain variables and methods can be used in accordance with the tree of the written code. The two properties described above are an introduction to the concept of local scoping:

function myFunction() {
         var name = “Hubgets”; //local variable created by myFunction()
         function displayText() {
                  alert(name); //use of variables declared in the parent function
         }
         displayText();
 }

Calling myFunction() will return an alert pop-up with the message “Hubgets”.

In the example above, we’re dealing with two nested functions:

  • myFunction() that creates the variable name;
  • displayText() that can access the local variable name created by the enclosing function.

Each variable created by any of the two functions has a limited lifespan and is reinitialized by every function call. The inner function displayText() has a major flaw, i.e. it cannot be used outside myFunction().

Finally, what is a “closure”?

A closure is an inner function that has access to the variables of the enclosing function – the scope chain. A closure has three scope chains:

  • Has access to its own scope, i.e. can access the variables stated in the function body.
  • Has access to the variables created by the enclosing function.
  • Has access to the variables created globally.

A closure has the following major properties:

  • Most important, the inner function has access not only to its enclosing functions, but also to their parameters.
  • The moment a closure is created, its entire environment is preserved as is. This means that the value of local variables is preserved as well. They don’t get “destroyed” anymore.
  • A closure can help you access variables outside a function.

Therefore, you can create a closure by adding a function inside another function, keeping in mind the properties described above. To better understand how that happens, let’s see an example and some use cases.

Example

In the example below, a closure is being created with the help of the functions addFirstName and showEntireName. These functions follow the conditions and the properties of a closure as described above.

function myName(my_last_name) {
         var last_name = my_last_name;
         var first_name = null;
 
          return {
            addFirstName: function(my_first_name){
            first_name = my_first_name;
               },
            showEntireName: function() {
              console.log(first_name + " " + last_name);
            }
           }
          }

...
 
var name = myName(‘Doe’);
name.addFirstName(‘John’);
name.showEntireName();

The program will display my name, i.e. “John Doe”.

When the function myName(‘Doe’) is called, an environment is being created. The local variable last_name is assigned a value that lasts in time. In this case, the variable no longer gets “destroyed” at the end of the function call. That is why, once the function addFirstName is called, the function showEntireName can display the concatenation of the 2 variables. This is a very important, highly used characteristic of the closure.

Also, please note that the functions creating the closure are public, which means they can be accessed globally.

Use case

Let’s assume we need to monitor something. Here are a few things you could do about it, but none of them is a solution. This is where you could used closures instead.

var counter = 0; //global
      function add() {
           counter += 1;
      }
      add();add();add();

After calling the function for 3 times, the value of the counter will be “3”, but with the compromise of using a global variable – which is not recommended.

function add() {
      var counter = 0; //local
           counter += 1;
      }
     add();add();add();

After calling the add function, the value of the counter will be “1” because each call starts with 0 and basically only the increment of the last call will be taken into consideration.

function add() {
  var counter = 0;
       function plus() {counter += 1;} //nested function
           plus();  
  return counter;
}

This could solve the problem under the condition that the function plus can be accessed globally.

Conclusions

You can use closures in Node.js to treat callbacks, in the asynchronous style. You can also rely on closures if you want to create something that can be manipulated outside a function without having to reinitialize it on each and every occasion. Closures are much like an abstraction mechanism that allows you to separate problems very clearly. The code is more compact, readable, organized and suitable for functional re-use.

I hope this article has shed more light on what closures are and how they work. Certainly, there’s more to closures – this is just an introduction. However, I’ll leave you with a complete example that sums up all the explanations above, an application that creates a “dynamic list” in JavaScript.

function node (value) {
           var val = value;
           var next = null;

           return {
               getValue: function(){
                   return val;
               },
 
               setValue: function(value){
                   val = value;
               },
 
               setNext: function(following){
                   next = following;
               },
 
               getNext: function() {
                   return next;
               }
           }
       }
 
       function list(value) {
           var start = new node(value);
           var end = start;
 
           return {
               add: function(value){
                   var foo = new node(value);
                   end.setNext(foo);
                   end = foo;
               },
               getFirst: function() {
                   return start;
               }
           }
       }
 ....
 var dynamicList=list(5)
 dynamicList.getFirst().getValue()
 5
 dynamicList.add(7)
 dynamicList.getFirst().getNext().getValue()
 7

I’ll be happy to answer any questions you have, so feel free to ask me anything in the comment fields below 🙂

Post A Reply