Archive for August, 2012

6Aug
There are 2 problems with creating classes in JavaScript. 1) if you create classes in separate files you may need some system to tie the files up together for speed purposes. 2) typically your might lose your function names while you debug if you aren’t careful. In other words, you might be seeing tons of anonymous functions when you debug. There is a balancing act that goes on here.
How to define a class and methods typically:
Method 1:
function MyClass() {
}
MyClass.prototype.myfunc = function(){
}
Method 2:
function MyClass() {
   this.myfunc = function(){
   }
}
Method 3:
var MyClass = {
   myfunc : function() {
   }
}
In all 3 of these techniques you lose the name of the function in the debugger. Why? Well because your functions are technically anonymous.
function() {}
vs
function bob(){}
So how can we make this happen? Well… how about this:
MyClass.prototype.myfunc = function myfunc(){}
Yea, that actually won’t work everywhere unfortunately, but this will:
function MyClass{
   function MyClass_myFunc(){
   }
   this.myFunc = MyClass_myFunc;
}
It is a bit repetitive, but this will help you find where issues are occurring in a debugger. You debugger will now state the issue came from MyClass_myFunc() instead of (?). I believe some modern browsers do actually convert the (?) to the right function, but I believe it stops at some point in the call stack. So this is great!
Well you might also wonder how to namespace? What is a namespace in javascript anyways? Well a namespace like anything other than a “primitive” in javascript is an Object. It is defined:
var mynamespace = mynamespace || {};
This will either define a namespace named “mynamespace” as a new object literal OR it will use the existing mynamespace object in the current scope. So to add a class to our namespace we would just add our class to it:
function MyClass{
   function MyClass_myFunc(){}
   this.myFunc = MyClass_myFunc;
   mynamespace.MyClass = MyClass;
}
The problem with this is that we have both: MyClass the global defined and mynamespace.MyClass. To prevent this from occurring we wrap everything up like this:
var mynamespace = mynamespace || {};
(function() {
   function MyClass{
      function MyClass_myFunc(){
      }
      this.myFunc = MyClass_myFunc;</span></div>
      mynamespace.MyClass = MyClass;
}})();
Using the power of closures we have limited our globals to 1. We ONLY have mynamespace exposed globally. Nowwwww, we got 1 other thought that we should think about. What happens if our class depends on other classes? I’ve been looking at a good way to mimic Node.JS’s commonjs library client side. I think require.js will work well for this. How we might want to define our files with require.js:
var mynamespace = mynamespace || {};
require(["jquery"], function($) {
   function MyClass{
      function MyClass_myFunc(){
      }
      this.myFunc = MyClass_myFunc;
      mynamespace.MyClass = MyClass;
}});
Maybe? I think this looks good. It mimics the functionality we had earlier by limiting our global usage. You might be wondering what require is doing. Well, basically it is acting like a map. You specify where jquery is located and if it isn’t include it will get included. You can do this with all your classes in the app.build.js file defined by require. Note, that this does to some degree break from our notion of joining files together to optimize a website. While I am still investigating this, it seems that once a dependency is loaded requirejs will not load it again. This means that require might actually test for the existence of the dependency and if it isn’t around THEN load that file. This should allow you to use require’s optimizer to pull in various portions of a project at load then the rest later. Still reading, but this seems like the most optimal setup! 🙂
By the way, using backbone.js also forces you to adhere to the above conventions!
Sources:
Share/Save