I use two main patterns, a singleton pattern and a constructor pattern. A singleton is an object which will have only one instance within an application. A constructor is a function which when invoked with the new keyword will create an object based on its definition. These objects are known as instances.
Constructor Pattern
A constructor pattern is something which JavaScript has native support for. Douglas Crockford has previously talked about this pattern at length.
function EventHandler() {
//constructor
//private members
var registeredEvents = [];
//public methods
this.registerHandler = function(func) {
if (typeof func === "function") {
registeredEvents.push(func);
}
}
this.fire = function() {
for (var i = registeredEvents.length-1; i >= 0; i--) {
registeredEvents[i]();
}
}
}
A constructor is simply a function which defines various members and contains its own variables and indeed other functions. You can also define constructor logic with a series of statements which do not declare methods or private variables or functions.
Its a fairly simple pattern and it is just as easy to use. To declare a new instance of this constructor, the code is simply this:
var myEventHandler = new eventHandler();
Singleton Pattern
My aim with a singleton is to have a highly readable object formation pattern which allows for private members and the exposure of a public interface. The syntax also must ensure that only one instance of the singleton can exist though of course there is nothing to stop the object being inherited from.
I also wanted the pattern to look similar to the constructor pattern above. This should make it easier to code and maintain.
For this example, I am using a simplified version of an object in JSquared. JSquared makes extensive use of this pattern as much of the library is built up from singleton objects. The object I am using here is the cookies object. For details on how to use this within an application of your own, look out for a post on the JSquared blog.
var cookies = new (function() {
//private members
var cookies = {};
//constructor
//get the current set of cookies
var currentCookies = document.cookie.split(";");
var cookie;
//loop through current cookies and add their values to the cookies collection
for (var i = currentCookies.length - 1; i >= 0; i--) {
cookie = currentCookies[i].split("=");
if (cookie.length >= 2) {
cookies[cookie[0]] = cookie[1];
}
}
//public methods
this.set = function(name, value, expiration) {
document.cookie = name + "=" + value + ";expires=" + expiration + ";path=/";
cookies[name] = value;
}
this.get = function(name) {
return cookies[name];
}
this.delete = function(name) {
this.set(name, "", -1);
delete cookies[name];
}
});
You will I am sure notice how similar this singleton pattern is to the constructor pattern above. The major difference is that the singleton pattern created the constructor as an anonymous function and then invoked an instance of that anonymous function immediately.
Just like when creating a new instance of a constructor, an object defined as per the constructor function will automatically be returned from the invocation. So in the example above, the variable cookies will contain the singleton.
The syntax may look odd, but it has proven itself very resilient and extremely effective. It allows for private members and functions, the public methods have access to those private members. It contains constructor logic and of course parameters can be passed in to the constructor just like they could be in the constructor pattern shown above.
As I seem to often say, its as simple as that!
6 comments:
Very very useful, I have started to use both of these patterns and have found them to be very effective so far.
It is so simple yet powerful.
Very nice. I'm learning javascript and I've found that javascript functions are extremely powerful. I've blogged about it myself. Also how did you highlight the syntax? Thanks.
Both very good patterns. Personally though I prefer the other singleton pattern
var myObj = function(){
// private area
// public return object
return {
init:function(){
}
}
}
Feels much cleaner to me but that's just a personal opinion
Hi James, I have been looking all over the internet as to why there are brackets around the singleton anonomous constructor function. :(
What do you think about the performance of recreating these methods on every object instance, rather than one time on their prototype? This is mainly why I have avoided the constructor function pattern you describe, despite its advantages.
I don't really comment on using the prototype in this example of a constructor. I definitely think the prototype should be used whenever it is sensible to do so as there is a performance gain. However, if few instances created and used and there are few functions on the object, then it becomes less of a concern. As in all things, use the correct tool at the correct time!
Post a Comment