Monday, June 18, 2012

Javascript Closures and few other Javascript concepts

Similar to Java's inner classes, JavaScript has something called Closures.

Before going into the details, let me explain the issue I was facing and why Closure was the right fit.

In my Java code, I had a native method like:

public native JavaScriptObject drawSomething()/*-{
//'menu' is variable to which we can add menu items
menu.addItem('Menu Item 1', 'someimage1', function() {
// Here goes the code which handles the event when 
//user clicks this menu item
});
}-*/;

In the above code, the method body is enclosed between /*-{ and }-*/. This marks the code as JSNI. JSNI is essentially more or less JavaScript code.

I had to add menuItems to the menu. In the above code (menu.addItem('Menu Item 1', 'someimage1', function()), the first parameter is the text to be displayed on the menu item, second parameter is the icon/image to be displayed for the menu item. Third parameter is a function definition. When a user clicks on this menu item, this function will be invoked.

I can even call like this:
menu.addItem('Menu Item 1', 'someimage1', myfunction);
function myfunction(){
//some code
}
where myfunction is the name of a function. That is, method-name can be passed as a parameter and JavaScript will invoke the method with that name.

Now I want to pass parameters to this new function.
Can I do like this:

menu.addItem('Menu Item 1', 'someimage1', myfunction('someString'));
function myfunction(str){
//some code
}
NO.
What happens when the above code is executed?
the myfunction(str) is invoked when the JavaScript engine executes the menu.addItem() method itself.
That is, it does not wait for the user to click on the menu item.

So how to pass variables to such methods?
Use Java Closures!

Solution is:
Move the menu.addItem() to a new method:
function myfunction(menu, str){
     function newfunction() {
          //Use the str parameter here
     }
menu.addItem(str, 'someimage1', newfunction);
}

In the above code, I wrote a new function named newmethod inside the myfunction().
This newmethod will have access to the parameters passed to its parent function, that is, myfunction. Here we can use the str parameter. The value for the str parameter was the 'Menu Item 1'.
That is because, I wanted to invoke a Java method with a parameter with value as the menuItem that has been selected by the user.

This is how we sue JavaScript closures.

Thanks to my colleagues Ganesh and Raj for helping me out solve an issue in Javascript using this concept.

Before I close, I would also like to mention about 'Invoking Java methods from inside JSNI' briefly:

function myfunction(menu, str){
     function newfunction() {
          //Use the str parameter here
          thisClass.@com.sample.MyClass::menuItemSelected(Ljava/lang/String;)(menuitem);

     }
menu.addItem(str, 'someimage1', newfunction);
}

In the above code, I am passing the text of the menuItem selected by the user to a instance method inside a Java class named MyClass in the package com.sample.

The syntax for invoking a Java method from JSNI is:
classobject.@fully_qualified_classname::method_name(syntax_of_parameter[s])(actual_parameter[s]);

Let me know if you have any questions.