Javascript Closures








Closures are functions that have access to variables from another function's scope.

This is accomplished by creating a function inside a function:


function createComparisonFunction(propertyName) {
/*w  w w .  j a va 2  s .c o m*/
    return function(object1, object2){
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];

        if (value1 < value2){
            return -1;
        } else if (value1 > value2){
            return 1;
        } else {
            return 0;
        }
    };
}
var compare = createComparisonFunction("name");
var result = compare({ name: "XML" }, { name: "CSS" });

The inner function's scope chain includes the scope of createComparisonFunction().





Closures and Variables

The closure always gets the last value of any variable from the containing function.

The closure stores a reference to the entire variable object, not just to a particular variable.

You can force the closures to act appropriately by creating another anonymous function, as follows:


function createFunctions(){//from   www .  j  av a  2s. com
   var result = new Array();

   for (var i=0; i < 10; i++){
         result[i] = function(num){
             return function(){
                 return num;
             };
         }(i);
   }
   return result;
}
console.log(createFunctions());

The code above generates the following result.





Block Scope

Anonymous functions can be used to mimic block scoping.

The basic syntax of an anonymous function used as a block scope (or a private scope) is as follows:

(function(){
     //block code here
})();

This syntax defines an anonymous function that is called immediately. This function is then called via the second set of parentheses at the end.

These private scopes can be used anywhere variables are needed temporarily, as in this example:

function outputNumbers(count){
  (function () {
       for (var i=0; i < count; i++){
           console.log(i);
       }
  })();
  //console.log(i);   //causes an error
}

In the code above, a private scope is added outside the for loop.

This technique is often used in the global scope to avoid naming collisions.

(function(){
    var now = new Date();
    if (now.getMonth() == 0 && now.getDate() == 1){
       console.log("Happy new year!");
    }
})();

Private Variables

JavaScript has no private members, but we can make a variable private by defining them inside a function.

Function arguments, local variables, and functions defined inside other functions are not accessible outside.

Consider the following:



function add(num1, num2){
   var sum = num1 + num2;
   return sum;
}

In this function, there are three private variables: num1, num2, and sum.

A closure inside a function would have access to these variables through its scope chain. In this way, we can create public methods that have access to private variables.

A privileged method is a public method that has access to private variables/functions.

We can create private variables inside a constructor.


function MyObject(){//from   ww  w  .  j a  v  a2  s .c  o m
    //private variables and functions
    var privateVariable = 10;

    function privateFunction(){
        return false;
    }

    //privileged methods
    this.publicMethod = function (){
        privateVariable++;
        return privateFunction();
    };
}

This pattern defines all private variables and functions inside the constructor. Then privileged methods can be created to access those private members.

Example

You can define private and privileged members to hide data that should not be changed directly, as in this example:


function Person(name){/*from  ww w. j  a v a 2  s . c o  m*/
   this.getName = function(){
      return name;
   };
   this.setName = function (value) {
      name = value;
   };
}
var person = new Person("XML");
console.log(person.getName());   
person.setName("CSS");
console.log(person.getName());   

The constructor in this code defines two privileged methods: getName() and setName(). Each method is accessible outside the constructor and accesses the private name variable.

Outside the Person constructor, there is no way to access name.

The code above generates the following result.

Static Private Variables

Privileged methods can be created by using a private scope to define the private variables or functions. The pattern is as follows.

(function(){
     //private variables and functions
     var privateVariable = 10;

     function privateFunction(){
         return false;
     }

     //constructor
     MyObject = function(){
     };

     //public and privileged methods
     MyObject.prototype.publicMethod = function(){
        privateVariable++;
        return privateFunction();
    };

})();

A private scope is created to enclose the constructor and its methods. The private variables and functions are defined first, followed by the constructor and the public methods.

MyObject which is defined without var becomes global and available outside the private scope.


(function(){//from   w ww.j  av a 2  s  .  c om
    var name = "";
    Person = function(value){
        name = value;
    };

    Person.prototype.getName = function(){
        return name;
    };

    Person.prototype.setName = function (value){
        name = value;
    };
})();

var person1 = new Person("CSS");
console.log(person1.getName());   
person1.setName("HTML");
console.log(person1.getName());   

var person2 = new Person("XML");
console.log(person1.getName());   
console.log(person2.getName());   

The code above generates the following result.

Module Pattern

Singletons are objects of which there will only ever be one instance.

The module pattern, as described by Douglas Crockford, augments the basic singleton to allow for private variables and privileged methods, taking the following format:


var singleton = function(){
    //private variables and functions
    var privateVariable = 10;
    function privateFunction(){//w w  w . j  ava2 s  . c o  m
        return false;
    }
    //privileged/public methods and properties
    return {

        publicProperty: true,

        publicMethod : function(){
           privateVariable++;
           return privateFunction();
       }
   };
}();