NovoGeek.com - Krishna's weblog

A technical blog on ASP.NET, AJAX, jQuery and .NET technologies

JavaScript closures is one of those topics which, I always thought, is beyond my head. Though several articles explain the concept, somehow, I was often confused.

I was working on a thick client application, which heavily uses lot of jQuery and JavaScript. I need a client side timer to run periodically, to keep user's session alive and so I was using JavaScript's native "setInterval()" method for my timer. Everything was fine, till I suddenly faced a weird problem.

Suppose, you have created a  global function which is to be fired periodically. In simple JS, it can be written as:

var timer=function (){ 
    console.log('my timer'); 
}; 
var timerId=setInterval('timer();',1000); 

This works perfectly well. Here the function "timer()" is at a window level and has global scope. So no issues so far.

However, to clean up the code, if you follow any of these patterns,  you will have good code, but setInterval will not work! See the below code for more clarity:

var TestObject=function(){ 
    var timerId; 
    this.timer=function(){ 
        console.log('test timer'); 
    }; 
    this.startTimer=function(){ 
        timerId=setInterval(function(){ 
            this.timer(); 
        },1000); 
    }; 
    this.stopTimer=function(){ 
        clearInterval(timerId); 
    }; 
}; 
 
var obj=new TestObject(); 
obj.startTimer(); 
obj.stopTimer(); 

In the above code, TestObject is the class which is holding the entire code, so that all my functions are not exposed to global window object. "timer()" is a public function which will be fired periodically and "startTimer()" is the function which will trigger the timer.

If you run the above code (you can quickly try in firebug console), you will get a JavaScript error - "this.timer is not a function". The reason is, setInterval() function will take the scope to window object and this will check for "timer()" at window level. Since you are wrapping it in "TestObject", "timer()" will not be found. To solve this scope problem, you need to use closures and store the instance of the class. So the "startTimer()" function should be like:

this.startTimer=function(){ 
      var inst=this; 
      console.log('startTimer this: ',this); 
      timerId=setInterval(function(){ 
          console.log('setInterval this: ',this); 
          inst.timer(); 
      },1000); 
}; 

The above code has two console statements. The “this” keyword in the first console statement prints the instance of TestObject, while the “this” keyword in setInterval function prints “window” object. This shows that setInterval function will take the scope to window level and hence it is not able to find “this.timer” in the first snippet.

Notice that we are storing the instance of TestObject class in a local variable "inst". Also notice that setInterval is using an anonymous function, which is forming a closure. In this anonymous funtion, we are able to access timer() function using "inst.timer()". This would solve the scope problem! setInterval function will be called for every 1 second and it will always have access to “inst.timer()”. This is the power of closures.

To explain closures in my words,  when there are nested functions, the child function will have access to local variables of parent function(which is as expected). But after the parent function has executed, the child function, when called explicitly, will still have access to the local variable of parent function. JavaScript garbage collector will not clear the value of the variable.

For a graphical explanation of JavaScript closures in jQuery context, please check BenNadel's blog. Ben explains the concept of closures very clearly in this article.

Happy coding :)


The goal of this article is to educate budding jQuery developers (who do not have much exposure to JavaScript), to write clean, readable, maintainable code. This is in fact, a pointer to articles written by several JavaScript gurus.

For a jQuery developer, who does not have good expertise of JavaScript object oriented programming concepts, the entire code of a JavaScript file would reside in the "$(document).ready()” function. This includes various events, ajax calls, their call backs, UI effects etc.

In the case of a large scale business application (having hundreds of JavaScript files, each file having few thousands of lines), this would mean a lot of effort during reviews, white box testing and especially maintenance. Therefore, apart from learning the library, knowledge of good practices of core JavaScript language is a must.

Here is a collection of some of the best links, which would change the way you code. Read them in this sequence :)

1. JavaScript Best Practices by Christian Heilmannhttp://dev.opera.com/articles/view/javascript-best-practices/

2. Show love to the object literal - http://www.wait-till-i.com/2006/02/16/show-love-to-the-object-literal/

3. Closures and lexical scoping in JavaScript - http://mark-story.com/posts/view/picking-up-javascript-closures-and-lexical-scoping

4. Private Members in JavaScript by Douglas Crockford - http://www.crockford.com/javascript/private.html

5. JavaScript programming patterns - http://www.klauskomenda.com/code/javascript-programming-patterns 

6. Five things to do to a script before handing it over to the next developer - http://www.wait-till-i.com/2008/02/07/five-things-to-do-to-a-script-before-handing-it-over-to-the-next-developer/

Out of all the JavaScript design patterns in link #5, these are quite popular:

 a. Singleton pattern [Thanks to HB Stone for explaining the concept in simpler terms]

 b. Module pattern [Thanks to Christian Heilmann for the contribution]

 c. Revealing module pattern [An updation to module pattern by Christian Heilmann]

I have tried these and like many others, I fell in love with the Revealing module pattern. The core of these patterns is the concept of closures. So make sure you are good at the basics!

Before trying out patterns, my jQuery code was like this:

$(document).ready(function() {
   //page load ajax call 
    $.ajax({
        type: "POST",
        url: "CTypesHandler.ashx",
        data:"{}",
        success: callBackFunction,
        error: function(){}
    });
 
    //ajax success callback function
    callBackFunction(response)
    {
        //process ajax response here...
    }
    
    //form validation code
    $('#FormId').validate(){
        //code for validation
    }
    
    //click events
    $('#submitButton').click(function(){
      //code for submit click event
    });
    
    $('#saveButton').click(function(){
      //code for save click event
    });
});

After trying out Revealing Module pattern, my jQuery code is very clean like this:

var mySamplePage=function(){
    var counter=0;
    
    var callBackFunction = function(response)
    {
        //process ajax response here...
    };
    
    var pageLoadAjaxCalls=function(){
        $.ajax({
            type: "POST",
            url: "CTypesHandler.ashx",
            data:"{}",
            success: callBackFunction,
            error: function(){}
        });
    };
    
    var bindEvents=function(){
        $('#submitButton').click(function(){
          //code for submit click event
            counter++;
        });
        
        $('#saveButton').click(function(){
          //code for save click event
        });
    };
    
    var validate=function(){
      $('#FormId').validate(){
          //code for validation
      };
    };
    
    var pageLoadOperations=function(){
        validate();
        pageLoadAjaxCalls();
        bindEvents();
    };
    
    return{
        init:pageLoadOperations
    };   
}
 
$(document).ready(function(){
    vare page= new mySamplePage();
    page.init();
});

To explain the differences in short, the first snippet has all code in document.ready function. This means, all variables, functions used are global. There is no modularization in the code. So if new events, UI logic are to be added, they add up to the mess.

In the case of patterns snippet, the code is clearly modularized. There are no global variables/functions. All members, functions are private. Only certain methods are exposed(by adding pointer in return statement). If new code has to be added in future, it can be added to the respective functions (like pageLoadAjaxCalls, bindEvents etc). Our document.ready is now very clean, and has control on what to be done, with ease.

Using good jQuery selectors gives optimized code; Using JavaScript design patterns gives clean and maintainable code. Happy coding :)


A beautiful presentation given by John Resig, creator of jQuery, at Google. John covers the latest improvements in the modern browsers namely Firefox 3.1, Safari 4.0, Internet Explorer 8.0, Google Chrome and Opera 10. You can find the video presentation here @ Youtube and the pdf format of the presentation here @ Slideshare. A must see presentation for the modern web developer :)

In ASP.NET, we are used to drag/drop server controls and quickly finish the task, though we do not concentrate much on how they work. The problem arises when JavaScript is disabled in the user's browser, as some of these controls do not work.

Also, if you have rich AJAX features in your site, they will fail miserably if JavaScript is disabled in the browser. Ideally, your client expects the site to work even when JS is disabled in the browser.

Here are some of the ASP.NET server controls which which depend on client script for their functionality:

  • The LinkButton and HtmlButton server controls require JavaScript. (However, the Button Web server control, the HtmlInputButton or HtmlInputImage controls work fine.)

  • Any Web server control whose AutoPostBack property is set to true need client script so that the control will post the page to the server.

  • The Validation controls require client script to support client-side validation. If the client does not support script, validation will run on the server only.

  • Gridview pagination, sorting will not work. Custom pagination has to be used
How to detect if JavaScript is enabled in the browser or not? Check this excellent article at Boutell.com.

So, for the site to still work without JavaScript, use <noscript></noscript> tag, place server side buttons inside the tags and write your server side code in the button click events. These tags will be visible only when JavaScript is disabled. So you will not face any issues when JS is enabled.

An irritating scenario: You need a link button to do a server side task, but it doesn't wont work without javascript.

Work around: Apply styles to server side button and make it look like link button :p
Here is the CSS code you have to write (works fine in all major browsers):

.NewLinkButton
{
background-color:Transparent;
border-style: none;
color:Navy;
cursor: pointer;
display:inline-block;
font-style:normal;
text-align: left;
text-decoration:underline;
}

Please check the MSDN article: ASP.NET Web Server Controls that Use Client Script for more valuable info.


Most of the AJAX introduction sessions give a demonstration of drag/drop features. I've attended an AJAX session 1 year back and wondered.."Will I ever be able to do such an amazing drag/drop cart?" Hehe..thanks to jQuery UI. Drag/drop  isn't a magic anymore!

Here is a demo of jQuery drag/drop shopping cart. Simply drag the items into the basket and total will be calculated. You may also remove the items from the basket, everything without postback.


All that started with a simple tweet by a Norwegian developer Erlend Schei. He came up with an idea to display an "Upgrade" message on IE6 browsers for his websites and suddenly, all major websites of Norway adopted it, thereby declaring a war on IE6. According to wired.com, even Microsoft is supporting the campaign.

Here is a fast spreading code, appearing on the internet, to support the campaign. This conditional code when included in our sites, appears as a message at the top when the site is opened in IE6 .
 
<html>
<head>
<title>No IE6 campaign!</title>
</head>
<body>
<!--[if lte IE 6]>
<style type="text/css">
#ie6msg{border:3px solid lightblue; margin:8px 0; background:AliceBlue; color:#000;font-family:Verdana;font-size:smaller}
#ie6msg h4{margin:8px; padding:0;}
#ie6msg p{margin:8px; padding:0;}
#ie6msg p a.getie7{font-weight:bold; color:#006;}
#ie6msg p a.ie6expl{font-weight:normal; color:#006;}
</style>
<div id="ie6msg" >
<h4>Did you know that your browser is out of date?</h4>
<p>You are using Internet Explorer 6. To get the best possible experience using our website we recommend that you upgrade your browser to a newer version. The latest version is <a class="getie7" href="http://www.microsoft.com/windows/downloads/ie/getitnow.mspx">Internet Explorer 7</a>. You may also try <a class="getie7" href="http://www.microsoft.com/windows/Internet-explorer/beta/default.aspx">Internet Explorer 8</a> which is available as a beta. The upgrade is free. If you're using a PC at work you should contact your IT-administrator.</p>
<p>You may also try other popular Internet browsers like <a class="ie6expl" href="http://www.opera.com">Opera</a>, <a class="ie6expl" href="http://firefox.com">Firefox</a> or <a class="ie6expl" href="http://www.apple.com/safari/download/">Safari</a></p>
</div>
<![endif]-->
</body>
</html>

Feel free to tweak it & use it.
In the world of browser compatibility problems, I think it's time for all of us to support this movement and reduce some pain to the developer as well as the customer...
 
Update(10th March, 2009):
The current BlogEngine theme itself looks distorted in IE6, as pointed out by one of my seniors'. So added the above code to my blog. You will get the above message when you open my blog in IE6 :)

The markup i.e., (X)HTML of your web page exists in many versions such as: HTML 4.01 Strict, XHTML 1.0 Transitional, XHTML 1.0 Strict etc. A web browser parses your web page and renders the content based on the version in which your markup exists. This information will be available to the browser though the DOCTYPE declaration. It should be declared before the <html> tag and looks like :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

Omitting DOCTYPE in the markup is one of the main reasons for cross browser compatibility issues. Sometimes, even if your mark up is valid (with XHTML and CSS), there might still be problems due to incorrect DOCTYPE.

Please go through these excellent links which explain the importance and implementation of DOCTYPE.



Caught this beautiful firefox plugin, YSlow on delicious and thought it's worth mentioning here.

From Yahoo Developer Network - YSlow analyzes web pages and tells you why they're slow based on the rules for high performance web sites. YSlow is a Firefox add-on integrated with the popular Firebug web development tool. YSlow gives you
# Performance report card
# List of components in the page
# Tools including JSLint
# HTTP/HTML summary
Dont miss it!

I was lucky to get a copy of the book Pro Javascript Techniques written by my hero, John Resig.
Initially, I thought it is just another routine book on javascript. But believe me, the first few pages of it will change ur notion of javascript from a mere validation stuff to a gr8 programming force of the web!

Check this link to learn more about the future of .net languages. You will learn more about .Net framework 4.0, Co-Evolution of VB.NET & C#, Dynamic Language Runtime(DLR) and more...

Also, make it a point to visit the official site of Microsoft PDC 2008, if you have not gone through it yet.  


  • Share/Save/Bookmark
  • Entries (RSS)
  • Comments (RSS)

About

ProfilePic Hi, My name is Krishna Chaitanya and I'm a web developer from Hyderabad, India.

This is my online abode where I write about various technical topics, my little experiments related to web development in ASP.NET, jQuery etc. More...


Friends


Archive