Examples of practical javascript object oriented design patterns

What object oriented design patterns do you use in your application's javascript, and why?

Feel free to post code, even if there is no formal design pattern attached to it.

I have written plenty of javascript, but I have not applied much object orientated patterns to what I am doing, and I am sure i am missing a lot.

59547 次浏览

I am a fan of the Module Pattern. It's a way of implementing extensible, non-dependent (most of the time) frameworks.

Example:

The framework, Q, is defined like this:

var Q = {};

To add a function:

Q.test = function(){};

These two lines of code are used together to form modules. The idea behind modules is that they all extend some base framework, in this case Q, but are not reliant on each other (if designed correctly) and can be included in any order.

In a module, you first create the framework object if it does not exist (which is an example of the Singleton pattern):

if (!Q)
var Q = {};


Q.myFunction = function(){};

That way, you can have multiple modules (like the one above) in separate files, and include them in any order. Any one of them will create the framework object, and then extend it. No manual need to check if the framework exists. Then, to check if a module/function exists in custom code:

if (Q.myFunction)
Q.myFunction();
else
// Use a different approach/method

I really like jquery's method chaining pattern, allowing you to call several methods on one object. It makes it really easy to perform several operations in a single line of code.

Example:

$('#nav').click(function() {
$(this).css('color','#f00').fadeOut();
});

The following are three popular JavaScript patterns. These happen to be easily implementable because of closures:

You may also want to check out:

The following is a Google I/O talk from 2008 presented by Diaz, where he discusses some topics from his book:

The singleton pattern is often very helpful for 'encapsulation' and organization stuff. You can even change accesibility.

var myInstance = {
method1: function () {
// ...
},
method2: function () {
// ...
}
};

cleanest way to implement a singleton in javascript

I really like the Decorator pattern with jQuery plugins. Rather than modifying plugins to meet your needs, write a custom plugin that just forwards requests and adds additional parameters and functionality.

For example, if you need to pass a set of default arguments around all the time, and you need slightly-different behavior that ties into business logic, write a plugin that does whatever pre and post work is necessary to suit your needs and passes your default arguments if those particular arguments aren't specified.

The main benefit of this is that you can update your libraries and not worry about porting library changes. Your code might break, but there's at least the chance that it won't.

Inheritance

I use a notation for inheritance that is based on ExtJS 3, which I find works pretty close to emulating classical inheritance in Java. It basically runs as follows:

// Create an 'Animal' class by extending
// the 'Object' class with our magic method
var Animal = Object.extend(Object, {
move : function() {alert('moving...');}
});


// Create a 'Dog' class that extends 'Animal'
var Dog = Object.extend(Animal, {
bark : function() {alert('woof');}
});


// Instantiate Lassie
var lassie = new Dog();


// She can move and bark!
lassie.move();
lassie.bark();

Namespaces

I also agree with Eric Miraglia on sticking to namespaces so the code above should be run within its own context outside the window object, this is critical if you intend your code to run as one of many concurrent frameworks / libraries executing in the browser window.

This means that the only way to the window object is via your own namespace / module object:

// Create a namespace / module for your project
window.MyModule = {};


// Commence scope to prevent littering
// the window object with unwanted variables
(function() {


var Animal = window.MyModule.Animal = Object.extend(Object, {
move: function() {alert('moving...');}
});


// .. more code


})();

Interfaces

You can also make use of more advances OOP constructs such as interfaces to enhance your application design. My approach to these is to enhance the Function.prototype in order to get a notation along these lines:

var Dog = Object.extend(Animal, {
bark: function() {
alert('woof');
}
// more methods ..
}).implement(Mammal, Carnivore);

OO Patterns

As for 'Patterns' in the Java sense, I've only found use for the Singleton pattern (great for caching) and the Observer pattern for event-driven functionality such as assigning some actions when a user clicks on a button.

An example of utilising the Observer Pattern would be:

// Instantiate object
var lassie = new Animal('Lassie');


// Register listener
lassie.on('eat', function(food) {
this.food += food;
});


// Feed lassie by triggering listener
$('#feeding-button').click(function() {
var food = prompt('How many food units should we give lassie?');
lassie.trigger('eat', [food]);
alert('Lassie has already eaten ' + lassie.food + ' units');
});

And thats just a couple of tricks in my bag of OO JS, hope they are useful to you.

I recommend if you intend to go down this road that you read Douglas Crockfords Javascript: the Good Parts. Its a brilliant book for this stuff.

One of useful patterns in javascript world is chaining pattern which is made popular by LINQ at first place, and also is used in jQuery.

this pattern enables us to call different methods of a class in chaining manner.

the main structure of this pattern would be as

var Calaculator = function (init) {
var result = 0;
this.add = function (x) { result += (init + x); return this; };
this.sub = function (x) { result += (init - x); return this; };
this.mul = function (x) { result += (init * x); return this; };
this.div = function (x) { result += (init / x); return this; };


this.equals = function (callback) {
callback(result);
}


return this;
};




new Calaculator(0)
.add(10)
.mul(2)
.sub(5)
.div(3)
.equals(function (result) {
console.log(result);
});

the key idea of this pattern is this key word, which makes possible accessing to other public member of Calculator fucntion.