Tuesday, January 8, 2013

The Reluctant JavaScript Developer

If  you are like most of the Java developers I know, you know "just enough" JavaScript to get by. You might not consider JavaScript a real language and would rather concern yourself with OOP and SOA and a host of other acronyms. JavaScript is indeed a language and a dynamic, flexible and very powerful one at that. Those same traits can also make it complex, hard to debug and error-prone. The good news is some of the same principles of OOP that you have learned over the years can also apply to JavaScript and by using a few simple techniques make your front-end code more manageable and hopefully save you from pulling too much of your hair out.

While I'm not suggesting you have to be an expert in everything you do, at least you should try to avoid it being a glaring weakness, especially if you make your living writing Web apps. I had the good fortune to work with some really good UI developers that have really helped me understand the front-end portion of web developing. The main thing they taught me is that with just a little studying and  practice can save you alot of headaches in the long run.

We might as well start at the beginning. Most beginners code everything into the page with a script block that looks something like this. This isn't all bad, I sometimes like to write my code in the page to get it to work like in step one before I re-factor.

 <html>  
 <body>  
 <script>  
 function one_test(){  
      alert('this is cool');  
      }  
 function two_test(){  
      alert('you bet it is');  
 }  
 </script>  
 </body>  
 </html>  

While that certainly works it is less than ideal. One problem with this is your web page becomes very hard to read and hard to change. And just like we  re-factor our Java code out into other classes we need to pull Javascript into external files. This has a few advantages like make code reusable, testable and being able to control when it is loaded in the DOM.

 <html>  
 <head>  
 <script src="my_file.js"></script>  
 </head>  
 <body>  
 <script>  
    one_test();  
    two_test();  
 </script>  
 </body>  
 </html>  

And my file (my_file.js).....


 function one_test(){  
      alert('this is cool');  
      }  
 function two_test(){  
      alert('you bet it is');  
 }  


Great now everything is in an external file and we're done!!! No, not quite. One problem we have is name spacing. Everything we declare is global and available everywhere. If we have another script and it has a function with the same name we will have a problem. As good Java developers we know this is not a good solution, and if you have ever had to debug something like this in some complex code with dynamically loaded pages it can be a real pain.

So what do we do? Well, just like Java gives us classes to encapsulate our code, JavaScript gives us something to encapsulate our code. The first one I will talk about is the Object Literal. And its coded like this.

 var myobject={  
      one_test:function(){  
           alert('this is cool');  
      },  
      two_test:function(){  
           alert('you bet it is');  
      }  
 }  

We are wrapping our functions, separated by commas, between brackets {..} and setting the result equal to a variable. And we change our HTML code to this

 <html>  
 <head>  
 <script src="my_file.js"></script>  
 </head>  
 <body>  
 <script>  
   myobject.one_test();  
   myobject.two_test();  
 </script>  
 </body>  
 </html>  

Now we could have another function called two_test but wrapped in another object and they wouldn't conflict, just like in Java if we have a method called foo() and its called from 2 different classes we could expect it to call different code.

You may also note that I now have two script blocks, one declaring the file and one calling. This is not really ideal and I'm doing it this way just for this example. Best practice is to use an external library to 'decorate' things like links and buttons and anything else with our JavaScript behavior so we could eliminate the second script block, but I'll save that for another post.

To a Java developer the best way to think of this is a Map and everything inside the Object Literal is a key value pair. That is why the syntax is name function pairs are separated by a comma, if we wanted a variable it would be similar
 var myobject={ 
      x:'test', 
      one_test:function(){  
           alert('this is cool');  
           return 'what is happening';  
      },  
      two_test:function(){  
           alert('you bet it is');  
      }  
 }  
And we would call it like
 <html>  
 <head>  
 <script src="my_file.js"></script>  
 </head>  
 <body>  
 <script>  
      alert(myobject["x"]);
 </script>  
 </body>  
 </html>  

So if we call the object with our key it will return a function and then the () will execute the function. So myobject is our reference to the map and one_test is the key which returns the function and the () executes it. To really see this, change the line myobject.one_test() to document.write(myobject.one_test), this will print out the body of the function to the DOM.

So, now all our functions are encapsulated and we are happy. Most of us stop here and that's OK. Just wrapping in Object Literals is often enough. However there is one more re-factoring we could do. We can wrap the Object Literal in a function. I know the abstractions are getting ridiculous a function wrapped in a function and if you are using a library like JQuery, you are probably wrapping it another function. Well the problem is everything in our Object Literal is public. We can't declare private variables or private functions. What we need is something like an interface, fortunately JavaScript gives us the ability to do that. Also the good news is that the calling code from the HTML will be the same. In this case our interface is going to return the same Object Literal that we were already referencing with some slight changes to the internal references.

Our final version will look like this

 var myobject=function(){  
      var my_str="--- really, really cool";
      function internal_one(){  
           alert('this is cool' + my_str);  
      }  
      function internal_two(){  
           alert('you bet it is' + my_str);  
      }  
      return{  
      one_test:internal_one,  
      two_test:internal_two  
      }  
 }(); 

Some things to note, I added () last lines of the function, this is to call the function so it will return the Object Literal into the global namespace. If I don't do this I have to change the calling code to myobject().one_test().

The return portion is the same as my Object Literal, and notice now I call the private variables from my functions and reference the private functions with internal names. Without getting too complicated, Javascript is able to take those internal references, bundle them up and pass them along with the Object Literal. This is known as a closure and it contains all the things from the execution environment to make the calls back into the functions.

So while these methods seem complex and hard to understand, with a little practice they do become common place. By applying these simple re-factorings to your JavaScript code, it will make it easy for the next developer to read and debug your code and you never know, that next developer just might be you.