Showing posts with label Javascript. Show all posts
Showing posts with label Javascript. Show all posts

Friday, February 17, 2012

Javascript closure for callbacks



Closures are useful mostly when invoking callbacks.

Like in case of Youtube iframe API's, it expects a global function to be defined.

eg.,

var yt_player = new YT.Player('elementId', {
                              width : Xpx,
                              height : Xpx,
                              events : {
                              'onReady' : onPlayerReady,
                              'onError' : onPlayerError
                              }
                             }); 

Where the documentation for the method can be found here.
The methods onPlayerReady, onPlayerError are expected to be in global scope.

But if you have Javascript based prototyping, i.e., Object-ness in your code and one of your objects needs to have a Youtube player as one of its properties, the code would become something like

MyObject.prototype.readyEvent = function(e) {
  this.yt_player = e.target
};

MyObject.prototype.loadPlayer = function() {
  var that = this;
  // that to make JS point to MyObject
  var yt_player = new YT.Player('elementId', {
                                width: ...,
                                height: ...,
                                events : {
                                'onReady' : that.readyEvent
                                }
                               });
While you would expect this to run, your instance of MyObject would not have yt_player anything.

The reason is the callback expects a global function, where this refers to DOMWindow object.

If you put a client side debugger through the browser in the readyEvent function, it will stop there, but if you do an inspection on this, it will say DOMWindow.

Javascript closure to the rescue. Your code would have to be like :


MyObject.prototype.loadPlayer = function() {
  var that = this;
  // that to make JS point to MyObject
  var yt_player = new YT.Player('elementId', {
                                width: ...,
                                height: ...,
                                events : {
                                'onReady' : (function(){
                                  var obj = that;
                                  return function(e) {
                                    obj.readyEvent(e);
                                  }
                                })()
                               });

The return function inside the onReady event returns a function which when gets executed, makes a call to the desired function (readyEvent in this case) of the instance of MyObj (obj in this case).

Monday, November 21, 2011

Hack for functions inside loop in Javascript


In one of my earlier blogs, I had mentioned that is not advisable to create functions inside a loop in Javascript, as any strict environment will result in an error in the JS file, such as a JsLint installation.

I had also cited an alternative approach to call a function inside the loop, instead of creating it inline.

But in some cases, it becomes imperative to have this functionality and even calling the function is not helpful.

Consider this piece of code


var obj = [ { a: ".link1", b: ".div1", c: ".div2"},
{ a: ".link4", b: ".div3", c: ".div4"},
...
];

for( var i = 0; i < obj.length; i++) { 

 var o = obj[i]; 
 $(o.a).click(function(e) { 
    e.preventDefault(); // some more operations... 
 }); 
}



Monday, October 24, 2011

Creating functions inside loops in Javascript

This is an ongoing effort to make Javascript a more robust programming language. So when one uses JSLint it complains about a number of bad coding practices.

One of its very rare occurrence is the creating of functions inside a loop.
Experienced programmers get into the habit of writing code like this:

var i;
for(i = 0 ; i < someValue; i++) {
  ...
  // some operations


  $(".a").onclick = (function() {
    $(this).href = // some manipulated code.
   });


} // end for


While this has become a standard way of operating in Javascript, this is a bad practice, because you are creating functions for every iteration of the loop. 
Since in Javascript, functions are also allocated memory and can be accessed with their name references anywhere in the code, that is after their point of declaration, this coding practice unnecessarily creates many instances (the word instance is also debatable in Javascript, as Object Oriented means differently in here) of the function.


In order to keep the existing functionality, the code can be re-factored to meet the standards in this way:


var doSomething = function(){
  $(".a").onclick = //some manipulated code.
};


var i;
for(i = 0 ; i < someValue ; i++) {
  ...
  // some operations


  $(".a").onclick = doSomething();


} // end for


The beauty of this style of coding is more evident when the function becomes complex and takes in values.