Diving into JavaScript Closures

By Amitai B.

Jul 27, 2016

JavaScript is an amazing programing language with beautiful parts. But it also contains very confusing and complex parts. Closures and scopes are probably two of the them. In his book JavaScript: The Good Parts (a must read for every web developer!) Douglas Crockford regards the JavaScript Scope as one of the awful parts. I couldn’t agree more. As a software developer that started his programming with languages such as C/C++, I had a hard time getting used to it and preventing bugs and errors in my programs.

But where there’s a pitfall, there is also a challenge, and one of the best ways to handle this challenge is by using Closures.

Contrary to scopes, Closures are one of the best features in JavaScript. They add a lot of depth and opportunities to develop clean and good code. But Closures are not easy to grasp and understand.

In this blog post, I will explain what is a closure, as well as how and when to use it.

Scope

Before jumping into Closures we must understand perfectly the JavaScript Scope and the Scope chain. Scope is the region in the code where the variable is defined.

In many languages such as C/C++, Java and more the scope of a variable is between two curly braces.

In JavaScript it is different.

The scope of a variable is within the function it was defined in. It means that we can write this code as follows:

function foo () {
  console.log(a); //undefined
  var a = 10;
  console.log(a); //10
}

A variable that is defined outside a function will be available inside the function:

var a = 10;
function foo () {
  console.log(a); //10
}

Local variable will be available inside inner function:

function foo () {
  var a = 10;
function goo () {
console.log(a);
}
  goo(); //10
}

If a local variable is defined inside the function with the same name as an outer variable, the local variable will take precedence:

var a = 7;
function foo () {
  console.log(a); //undefined (although there is a global variable a)
  var a = 10;
  console.log(a); //10
}

ES6 (ES2015) introduced a new reserved word: letlet allows you to define a blocked scope variable. This makes a lot of sense and I recommend you use it a much as possible to prevent bugs.

The scope chain and variable resolution

If a variable is being used in a function, the Javascript will execute a variable resolution: It will start by searching it in the local scope, if it is not there, it will start climbing up the function tree until it reaches the global object.

The global object is a regular JavaScript object whose properties are available to all functions; in client-side JavaScript, the Window object serves as the global object.

When the JavaScript interpreter starts (or whenever a web browser loads a new page), it creates a new global object and gives it an initial set of properties that define.

The scope chain of a function is the list of all available variables of this function. It is the scope of the function.

Closures

JavaScript uses lexical scoping, which means that the function will be executed with the variables that was in effect when the function was defined rather than the scope that was when it was invoked.

How JavaScript does it?

The JavaScript function contains not only the code of the function but also its scope chain.

Each time a JavaScript function is invoked, a new object is created to hold the local variables for that invocation, and that object is added to the scope chain.

The combination of the code and the scope is a closure.

The scope of all the global function are the same because they are exposed to the same variables. Nested functions have different scope, and this can lead to very interesting implementations.

Using Closure adds a lot of power to a program. Let’s see an example that demonstrates this:

I will implement a counter without a closure and indicate its limitation:

var counter = 0;
var increment  =  function () {
console.log(counter);
counter++;
}

increment();  //0
increment();  //1
increment();  //2

What is the weakness of this implementation?

The problem is that we can either change the counter variable or even change its type which can lead to bugs and errors.
 
Let’s try to implement it with a closure:

var increment = function () {
var counter = 0;
return function () {
    console.log(counter);
    counter++;
  }
}
myCounter = increment();
myCounter();  //0
myCounter();  //1
myCounter();  //2

This time, the counter is in the scope of the increment function and in the anonymous nested method. When we invoke the increment(), the JavaScript returns the anonymous function bound to its scope chain (with counter). When we invoked myCounter(), counter is available inside and acts as expected. The counter variable is available only inside the increment method, and its nested functions, which means that no one can change it from the outside. It is much safer and robust.

How dose counter is not garbage collect after increment method is done?

As a C# or java programmers, we are used to that the variables in a function are allocated on the stack, and when the function is over they are not available anymore. In JavaScript it is different. When the function returns, that variable binding object is still available if there were nested functions; only if there are no more references to the binding object it gets garbage collected.

Closures in practice

We understand that we have a powerful tool that can empower our programs. In the next section, I will show some of the cases that closures really facilitate.

Encapsulation

Encapsulation is hiding private properties of our implementation from the outside world. It help us create robust programs that will not break if another code in the programs uses the same variables names.

JavaScript doesn’t have out-of-the-box encapsulation. Closures are perfect for encapsulation:

var person = function () {
  var name;
  return {
    getName: function () {
      return name;
    },
    setName: function (n) {
      name = n;
    }
  }
}

var myPerson = person();
myPerson.setName('Robert Smith');
console.log(myPerson.getName());

name is protected from outside. It also enables us to add validation check when setting a name.

Callback and events

Closure’s ability to keep the scope allows us to use callbacks for asynchronous functions, and also to pass parameters to it. The callback is called after it is ended, but the scope is still available.

var asyncCall = function (callback) {
  var message = 'callback is called';
  setTimeout(function() {
    callback(message)
  }, 1000);
};

asyncCall(function (message) {
  console.log(message);
});

Emulating private function

With closures we can implement private function which can only be called from inside another function. This is very useful for “hiding” the inner implementation, and also for creating modules by using the module pattern. See the following example for a very simple module:

var calculator = (function() {
  return {
    add: function(a, b) {
      return a + b;
    },
    subtract: function(a, b) {
      return a - b;
    },
    multiply: function(a, b) {
      return a * b;
    },
    divide: function(a, b) {
      return a / b;
    }
  };
})();

console.log(calculator.add(1,3)); //4
console.log(calculator.subtract(5,3)); //2
console.log(calculator.multiply(2,3)); //6
console.log(calculator.divide(9,3)); //3

Generators

Closures are a perfect fit for generators because they hold their state.

function sequence() {
  var count = 0;
  return function ()
  {
    return count++;
  }
}

idSequence = sequence();
console.log(idSequence ()); //0
console.log(idSequence ()); //1
console.log(idSequence ()); //2

Conclusion

JavaScript is a very interesting and challenging programming language. On one hand, it has a lot of pitfalls that can break the code, and on the other, it offers the developer advanced tools for creating clean and robust programs.

Closures are one of its best features. The developer can use it for many techniques and pattern and elevate his code. Encapsulations, modules and callbacks are some of the usages.

As a JavaScript developer, it is very important to know how to use this tool. It can add a lot of value.

References

Leave a Reply