JavaScript Closure Example

Posted: September 2nd, 2011 | Author: | Filed under: Uncategorized | Tags: , | Comments Off

It has taken me time to fully understand the concept of closures in JavaScript. Here is an example of code that I rewrote so that we can use closures and get the thing to work the way we actually want it to.

The situation:
We have a set of buttons and we have to attach on-click handlers to them. These handlers should be called with parameters that are button dependent i.e., the innerHTML of the text box next to that particular button or say we need some attribute of the button (data-value, or some custom attribute).

We want to attach a function inviteUserToGroup with the specific parameters as event handlers to all the buttons.
So we initially wrote :

//add event handlers to invite buttons
var inviteBtns = $$('.inviteBtn'); //Prototype to get an array of elements with this class name
var len = inviteBtns.length;
var i;
var groupIdForUser;
var detailsForUserInGroupName;

for(i=0;i<len;i++){
    groupId = $('groupIdForUser'+i).innerHTML;
    details = $('detailsForUserInGroupName'+i).innerHTML;
    //Protoype syntax to attach event handlers 
    //Event.observe(element,event,handler)
    Event.observe(inviteBtns[i],'click',function(){
        inviteUserToGroup(groupId,i,details);});
}

function inviteUserToGroup(a,b,c,d){ doSomething();}

So, we attach inviteUserToGroup method with the parameters. Since we enclosed the handler as a function, one can assume that due to the scope of the function, it should work fine and the event handler will be called with the correct parameters. That doesn’t work that way. All the event handlers get called with the value of i = len. You thought closures would work here, but it does not.
So what do you do? Create a real closure. The following code does that

/* DOES NOT WORK
Event.observe(inviteBtns[i],'click',function(){
    inviteUserToGroup(groupId,i,details);});
*/

Event.observe(inviteBtns[i],'click', 
    (function(gId,i,dtls){
        return function(){
                   inviteUserToGroup(gId,i,dtls);
               }
        })(groupId,i,details)));

So what is happening?
1) Create an immediate anonymous function which takes in the parameters that you want in your handler.
2) In the anonymous function return the actual function with parameters that you want to call. In this case we return inviteUserToGroup() with the parameters.
The important point to understand is that, the immediate function will execute and hence have the current values of groupId, details and i, which are passed to it. Due to the closure, the inner function (which is returned) has access to these values even after anonymous function has completed execution. So, inviteUserToGroup is attached to each button with the correct parameters.

For completion, another way of doing this is

Event.observe(inviteBtns[i],'click',
    'inviteUserToGroup('+groupId+','+i+',\''+details)');});

Not recommended by many people as this uses the eval function to evaluate the JavaScript inside the quotes.

Is there a better (maybe more legible) way of doing this? Let me know!


JavaScript Notes – 1

Posted: August 19th, 2011 | Author: | Filed under: technical | Tags: , | Comments Off

My notes on JavaScript Patterns. This is just a part of the patterns covered by Addy Osmani and those covered by Stoyan Stefanov

**Disclaimer**: The code examples below are modified examples from JavaScript Patterns

Namespaces
Using global variables and functions in JavaScript can lead to smashing of variables as the code base grows. So a simple way of handling namespaces is

var NxJ = {};
NxJ.property1 = "Name is Nadu";
NxJ.method1 = function(){console.log("name is bond, james bond");}

// if you want to add modules
NxJ.modules.module1 = {};
NxJ.modules.module1.data = {"a":1,"b":2};

var moduleToBeUsed = NxJ.namespace("NxJ.module1.module2.module_n");

The variable names keep getting larger and larger. A way to handle this is to create a function called namespace, that can parse the module name and return only that module with all the methods. Useful when you are using big libraries like YUI (they have different modules for DOM, Events etc)

Private properties, Module and Revealing Module
By default everything is public

var myObj = {
	myName : “Nadu”;
	getName = function(){
		return myName;
	}
};
console.log(myObj.myName); // accessible

So a way of fixing this is

myObj = ( function(){
	// a var before myName - makes it private
	var myName = “Nadu, the Private”;
	return: // yes return an object
	{
            getName = function(){
               return myName;
            }
	};
}());

console.log(myObj.myName); // inaccessible now
console.log(myObj.getName()); // this is the right way to get it

Points to note -

  • Immediate function call – so what value does myObj get?
  • var before myName makes it private because of closure
  • getName is a privileged function

Lets add namespaces now,

var NxJ = {};
NxJ.coolModule  = ( function(){
	// a var before myName - makes it private
	var myName = “Nadu, the Private”;
	var yourName = “Someone else”;

	return:
	{
              getName = function(){
		   return myName;
	      },
	      setName = function(n){
			myName = n;
              }
	};
}());

So that’s the Module pattern!
Since we have reached alive till here, we will jump to the Revealing module pattern, which is nothing but a simple extension of the Module pattern.
In the Revealing module pattern, you define all the properties as private in the object and then return only those that you want to be made public

var NxJ = {};
NxJ.coolModule  = ( function(){
	// a var before myName - makes it private
	var myName = “Nadu, the Private”;
	var yourName = “Someone else”;
        var getName = function(){return(myName);};
	var setName = function(n){ myName = n;}

	return:
	{
		getName: getName,
		getTheAwesomeName: getName // sort of an alias!
	};
}());
console.log(NxJ.coolModule.getName());
console.log(NxJ.coolModule.getAwesomeName()); // this works too

There are 2 advantages of this pattern, one is that it’s a little more cleaner than the Module pattern and two you can have these aliases. One can create a JavaScript API and then just return all that is public.

Be careful!

var NxJ = {};
NxJ.coolModule  = ( function(){
    // a var before myName - makes it private 
    var student = {"name":"Nadu", "age":"18-till-i-die"};
    var getStudent = function(){ return student; }    
    
    return    {
        getStudent: getStudent
    };
}());
var stud = NxJ.coolModule.getStudent();
console.log(NxJ.coolModule.student); // not possible
console.log(stud.name); // says Nadu
stud.name = "Narayanan Ramakrishnan"; // trying to modify it
var stud2 = NxJ.coolModule.getStudent();
console.log(stud2.name); // prints Narayanan Ramakrishnan - Hey WTF ?

This is because for arrays and objects, JavaScript returns the reference, so its accessible to anyone who has the reference. So one way of handling this is to return a new object that has properties that the caller is interested in. Called the Principle of Least Authority which states that you should never give more than intended. One way of doing this in the example above is, instead of giving the caller everything, you can break it down into functions getName(), getAge(). There is another approach using a general purpose cloning function, but that will be covered later.

More notes to follow in another post.
Further reading
A beautiful explanation of Module Pattern by Twitter engineer Ben Cherry
Signing off treat – www.jsfiddle.net