My Blog List

Friday, July 9, 2010

Simple JavaScript Programming Techniques

 

So I have been working on JavaScript for a little while now and gathered up a few points I thought I would share .This is my first blog post ever, so please forgive (but do let me know) any defects. I have tried to not get too detailed as I am afraid it will overload readers. Needless to say, I will be more than happy to discuss and revise the content to further improve it.

1. Declare commonly used objects globally to improve performance and to reduce your file size.

eg.: Declare the document object and window objects globally and use the references in your code.(I generally like to start my global variable names with a '$' sign,but that's just my naming convention. So at the top of my JS file I would say:

        var $doc = document;var $win=window;)

2. Wrap functions in logical namespaces:  For example if you have a bunch of utility functions , you could wrap them in a "Utility" namespace (as shown below) and call the functions using Namespace.function() syntax. 

[So in this example to call replaceAll(), you would say: Utilities.replaceAll("arg1","arg2","arg3") ] 

  1: var Utilities = {
  2:          stopEventPropagation : function(e) 
  3:                                  {    
  4:                                      if (!e)
  5:                                          e = window.event;                        
  6:                                      if (e.cancelBubble)
  7:                                          e.cancelBubble = true;
  8:                                      else
  9:                                          e.stopPropagation();
 10: 
 11:                                  },
 12:                  formatText      : function(text,color,isBold)
 13:                                  {
 14:                                      // implementation..            
 15:                                  },
 16:                  replaceAll        :function (Source,stringToFind,stringToReplace)
 17:                                  {
 18:                                     // implementation..
 19:                     
 20:                                  }
 21:                      }
This has the following advantages:

  • Avoid variable/function name clashes with (potentially) similarly-named variables in other JS libraries/files.
  •   Makes the code much more readable for other people.(Imagine if your HTML file references 5 JS files and you encounter a method call like validate(), you would have to go look in all to find the where validate() is implemented.I personally try to place one namespace per file,so Utilities namespace would be in Utilities.js, so anyone would know exactly where to look.)
  •   Provides an elegant way to create grouped constants,which improves readability.
  1:    var XHROReadystates {
  2:         UNINITIALIZED :0,    /** The initial value. */
  3:         OPEN :1,             /** The open() method has been successfully called, */
  4:         SENT :2,             /** The UA successfully completed the request, but no data hes yet been received. */
  5:         RECEIVING :3,        /** Immediately before receiving the message body (if any). All HTTP headers have been received. */
  6:         LOADED :4            /** The data transfer has been completed. */
  7:     }

3. Using User-Defined Attributes: HTML allows elements to have user-defined attributes. They can be accessed/modified in the same way as standard attributes.This is a powerful mechanism and can be used for both UI and functionality. A note on accessing attributes, IE allows access to the attributes using the (.) dot operator but this is not the W3C Standard and does not work on DOM compliant browsers like FireFox and Safari.Always use the W3C standards-compliant get/setAttribute methods to use attributes.


Here is an example of a user defined attribute and how it may be used.

eg:

  1: <input type="text" required="true" id="myTB".... 
Here required is not a standard HTML attribute (for simplicity's sake lets not consider HTML5's required attribute) 
Here is a way to use it to perform simple validation:
 
  1: isRequiredFieldsFilled	  : function ()/* Function to test if "required" input elements have been filled */
  2: 			   {
  3: 				   /* initialize result flag */
  4: 				   var isValid = true;
  5: 				   /* We are going to test the following element types */
  6: 				   var types = new Array("SELECT","INPUT","TEXTAREA");
  7: 				   /* For each type */
  8: 				   for(var i=0;i<types.length;i++)
  9: 				   {
 10: 					   /* Get all elements of that type */
 11: 					   var elems = document.getElementsByTagName(types[i]);
 12: 					   /* For each of these elements */
 13: 					   for(var j=0;j<elems.length;j++)
 14: 					   {
 15: 						   /* Ignore hidden fields */
 16: 						   if(elems[j].type=='hidden')
 17: 							   continue;
 18: 						   /* Reset color */
 19: 						   Utilities.setInvalidColor(elems[j], false);
 20: 						   /* Test if the required attribute exists,if so check if it is empty */
 21: 						   if(elems[j].getAttribute("required")!=null 
 22: 		    					&& (elems[j].getAttribute("required")==true 
 23: 			  	 				&& elems[j].value=="")
 24: 						   {
 25: 							   /* Mark as unfilled */
 26: 							   Utilities.setInvalidColor(elems[j], true);
 27: 							   /* Set result flag */
 28: 							   isValid=false;
 29: 						   }
 30: 					   }
 31: 				   }
 32: 				   /* After checking all elements,now check if anything has set the result flag */
 33: 				   if (!isValid) {
 34: 					   /* Alert the user */
 35: 					   alert('Please fill required fields!');
 36: 				   }
 37: 				   return isValid;
 38: 
 39: 			   }
4. Do Feature-detects, NOT browser detects

Doing this allows you to be be detached from the changes made by the browser vendor.Consider the example below, which tests if the browser is IE and if so executes someIEMethod else it executes a  DOM compliant someDOMMethod. Consider the future possibility that IE may decide to be DOM compliant and provide implementation for the DOM method someDOMMethod() and in time,deprecate someIEMethod (). This code would break then. 

  1: if (navigator.userAgent.indexO(”MSIE”) > —1)
  2:     someIEMethod();/* say, a non-DON coin1iant function */
  3: else 
  4:     someDOMMethod();/* say, a DOM compliant function */
  5: 

Here is a more real-world example which prevents event propagation depending on the browser.Consider evt to be the event object. This is not a good way to do it:

  1: if (navigator.userAgent.indexOf('MSIE') > —1)
  2:     evt.cancelBubble = true;/* lE specific */
  3: else 
  4:     evt.stopPropagation();/* DOM compliant */
  5: 
  6: 

A better way is:

  1: if (evt.cancelBubble)
  2:   evt.cancelBubble = true;
  3: else
  4:   evt. stopPropagation();
  5: 



[A note: For some situations a browser detect may still be required, most typically to apply browser specific CSS like opacity etc.]