A Simple, Powerful, Lightweight Class for jQuery
jQuery's functional programming style is downright elegant for manipulating the DOM. But it lacks the structure and code reuse patterns that professional scripters need. John Resig's Simple Class inspired, jQuery.Class is a lightweight, but powerful class-like system that bridges the gap between jQuery's functional programming style and Object Oriented Programming.
Features
- Static and prototypal inheritance
- Introspection
- Namespaces
- Setup and initialization methods
- Easy callback creation
Download
jquery.class.js (minimized 2kb)
Demo
Extend a tabs widget to a history tabs widget demo.
Documentation
JavaScriptMVC's Class docs.
Use
To create a monster class with static and prototype properties:
$.Class.extend("Monster",
// static properties
{
count: 0
},
// prototype properties
{
// constructor function
init : function(name){
//save the name
this.name = name;
this.energy = 10;
//increment the static count
this.Class.count++;
}
})
//create a monster
var dragon = new Monster('dragon');
Inheritance
To extend (or inherit) from a class just call .extend on the class and provide the new name of your class and the static and prototype properties:
Monster.extend("SeaMonster",{},{
swim : function(distance){
this.energy -= distance
}
})
If you want to call an base class's static or prototype method from the extended class:
SeaMonster.extend("LochNessMonster",{},{
swim : function(distance){
this._super(distance/2);
}
})
Notice how _super calls the base class's method.
Introspection
You can access the full and short name of the class for groovy introspection techniques. The following uses the class's name to change where the ajax request is sent:
$.Class.extend("Model",{
findAll : function(success){
// use the class's name to find items
$.get('/'+this.shortName.toLowerCase()+'s',
success,
'json')
}
},{});
// create a task model
Model.extend('Task')
//use it to make a request to /tasks
Task.findAll(function(tasks){
alert(tasks.length);
})
Namespaces
Namespaces are a GREAT idea. It's nice when code doesn't clobber each other.
$.Class.extend("MyCo.Project.MyClass");
MyCo.Project.MyClass.shortName //-> MyClass
MyCo.Project.MyClass.fullName //-> MyCo.Project.MyClass
Setup and Initialization Methods
When a class or instance of a class is created, setup and init methods are called on the class or instance. Setup is called before init and can be used to normalize arguments to init. Init is the class or instance's constructor function. But unlike normal constructor functions, you don't have to worry initialization code that will prevent further inheritance*.
The following makes sure all classes extending Controller will have their init function called with a jQuery element instead of an element:
$.Class.extend("Controller",{
setup : function(el){
arguments[0] = jQuery(el);
return arguments;
}
})
// A dummy tabs class
Controller.extend('Tabs',{
init : function(el){
this.element = el;
}
})
var tab1 = new Tabs($("#foo")),
tab2 = new Tabs($("#bar")[0]);
//call jQuery methods on element
tab1.element.show();
tab2.element.hide();
*You probably won't need setup methods, but it's cool if you need a lot of pre-processing for extending classes. The problem with normal constructor functions is that they typically need to be callable without arguments to be able to setup a correct prototype chain.
Easy Callback Creation
Similar to jQuery's proxy, Class provides a static and prototype callback function that returns a callback that has 'this' or the context set to the Class or instance.
The following uses callback to return a function that will call the new task's show method with 'this' set to the new task.
$.Class.extend("Task",{
init : function(name){
this.name = name
},
get : function(){
$.get('task',
{name:this.name},
this.callback('show'),
'text')
},
show : function(instructions){
alert(this.name+instructions)
}
})
new Task("dishes").get()
The callback function lets you curry arguments and even gets a little Aspect Oriented Program-ish and lets you chain multiple callbacks*:
$.Class.extend("Task",{
init : function(name){
this.name = name
},
get : function(date, callback){
$.get('task',
{name:this.name},
// call show, then callback, curry date
this.callback(['show', callback], date),
'text')
},
show : function(date, instructions){
// return arguments for next function
return [this.name, date, instructions]
}
})
new Task("dishes").get(
new Date(),
function(name, date, instructions){
console.log(name, date, instructions);
}
)
*Chaining callbacks is helpful when there are multiple processing steps before some final callback is called. It makes it so you don't have to curry the final callback over and over again. ;
Conclusions
Use classes where appropriate. There has been some fun poked at classy-ing up jQuery. But there is an important difference between an API for modifying the DOM and a sortable-paginated-groupable grid.
jQuery lacks a clear and repeatable pattern for organizing code. It also lacks tools to extend and add functionality to existing widgets. This is to jQuery's strength. It makes jQuery useful to everyone.
But, as code gets more complex and teams get bigger, the need for patterns and tools to bridge the jQuery to Object Oriented Architecture gap becomes unavoidable. We hope jQuery.Class can help.
Subscribe to:
Related Content
Recent Posts
- StealJS - Script Manager
- JavaScriptMVC Features
- jQuery's Object Literal Coding Conventions
- Why jQuery Needs JavaScriptMVC Part 2
- Ben Alman is Awesome
- Why jQuery needs the Enterprise
- Why jQuery needs JavaScriptMVC
- How FuncUnit works
- FuncUnit - Fun Web Application Testing
- Tips on Hiring a jQuery Consultant
JavaScript development, design, and consulting.