Social Icons

twitterfacebookgoogle pluslinkedinrss feedemail

Sunday, July 26, 2009

How to create a namespaced JavaScript Object/Class

One of the most important things you can do when creating JavaScript Objects/Classes for reuse throughout your web application or website (or both) is to utilize a namespace that will ensure no pollution occurs when you start to use other JavaScript libraries and APIs. Just like C++ introduced the concept of namespaces and Java introduced the concept of packages, it's good to ensure your code is isolated enough so that it's guaranteed (well, mostly) to work the same no matter which libraries you wind up utilizing.

Creating JavaScript classes isn't hard. It's simply a matter of doing something akin to the following:

function Foo(theBar) {

this.bar = theBar;

this.getBar = function() {
return this.bar;
}
}
That's pretty much it. You can add additional methods as you see fit. You can now instantiate class Foo and execute getBar() as follows (note that I don't define what the bar parameter is, but it can be anything - here it is an integer):

var f = new Foo(1);
alert("bar is: " + f.getBar();

The problem with this is that anyone can add any method to your class by calling and executing:

// add function
Foo.prototype.bat = function() {
alert("new function!");
}

// execute function
var f = new Foo(1);
f.bat();
This is kind of bad, yes? Namespacing your class makes it harder (and in one case as we'll see below, impossible) for people to do this effectively making your class "final" in that no methods can be added, polluting your class. So, how do we namespaceify our class? Simple. Change the above to the following:

var Foo = function(theBar) {

return {

method1 : function(message) {
alert(message);
},

method2: function(anotherMessage) {
alert(anotherMessage);
}
};
}();
Now, if someone tries the same 'Foo.prototype.bat = ...', they will get a JavaScript error saying prototype doesn't exist - because it doesn't.

One downside to this is that all the methods defined above are "static" meaning that they can be called via 'Foo.method1()' or 'Foo.method2().' We can add a constructor function to the namespace and while the "outer" class Foo is still immutable to prototype, we cannot prevent methods from being added to instances of the constructor function - however, using a namespace will better protect against namespace pollution. Here's the final example:

var Foo = function(theBar) {

var privateField;

function privateFunction() {
// contents
}

return {

method1 : function(message) {
alert(message);
},

method2: function(anotherMessage) {
alert(anotherMessage);
},

// a "constructor" function
aClass: function(theFoo, theBar) {

this.foo = theFoo;
this.bar = theBar;

this.getFoo = function() {
return this.foo;
}

this.getBar = function() {
return this.bar;
}
}
};
}();
Notice that we've added a private field and private methods as well as a constructor function with private fields and member methods.

0 comments:

Post a Comment