Using Inheritance Patterns to Organize Large jQuery Applications

I want to introduce/reinforce a pattern for developing large applications with jQuery. I did not invent any of this, but I find that the resources that describe this technique are few and far-between.- so I'm taking a shot at it.
By and large, when using jQuery, developers seem to forget the paradigms they learned for well structured code in other languages. This is likely due to the fact that jQuery is effectively neutral when it comes to your structural methodology or inheritance patterns, and therefore doesn't push someone in any one direction. Many times in other libraries (See Dojo Declare/Provide/Require, or MooTools Class, etc.), a paradigm is used and exclusively offered, and then code generally ends up more uniform than the oh-so-common-massive-jquery-indented-chains that I'm sure you've seen .
I'm not going to necessarily suggest that you use any single inheritance pattern, as there are many options, and each makes sense for different people and different situations. I do however suggest that you know your options. There are a few good reads on the topic of Inheritance in javascript, and I would strongly suggest people read at least a bit of the following:
- Javascript: The Good Parts (Chapter 5) -Douglas Crockford
- Prototypal Inheritance in Javascript -Douglas Crockford
- Object-Oriented Javascript -Stoyan Stefanov
- Javascript Override Patterns -Andrea Giammarchi
- Simple JavaScript Inheritance -John Resig
Choosing your form of modularity is an important step. If you come from a background of highly-classical inheritance (I learned Java in school, so...I know that world) then perhaps starting with a classical implementation is going to be your best choice. If you are trying to stay slim and do the things a little more in the "JavaScript way" (a term that means essentially nothing), then you might try to use prototypal inheritance. For my examples, any form of inheritance will at least work on most accounts.
I'll jump straight to a code example of this technique in use, and then describe it's setup and structure:
<div id="mySpeaker"></div>
Then we'll run our javascript:
$(function(){
// Call a custom plugin for your object on a dom element
$('#mySpeaker').speaker({'name': 'Alex'});
// Have quick access to the actual speaker object
var mySpeaker = $('#mySpeaker').data('speaker');
// The interface of the object that you build can
// wrap more complex dom manipulations that are
// separated from actual program logic.
mySpeaker.speak('I am a speaker.'); // Results in a dom update
// This shows automatic access to correct element in the dom
});
And the html now looks more like this:
<div id="mySpeaker"> <h1>Alex</h1> <p>I am a speaker.</p> </div>
The key here is that we didn't have to call something like $elem.append('Alex') nor did we even have to consider what would happen when a speaker object was called with the speak() function. I consider this to be the key to modular development. This level of abstraction helps keep the how and the what separated (or "loosely coupled" - if you like buzzwords). The other thing that was important to note is that after we instantiate the plugin, we have a clear two-way path between our Object and our Dom Element - both have an easy way to immediately access the other. This is important, because we often have different points of entry to jump-start a routine, so being able to access the part that you need quickly and easily is important.
Implementing this technique is pretty simple, and should actually take less brain power to set up than traversing through the dom in your head to figure out a crazy chain.
Let's start with the Speaker object.
/**
* Object Speaker
* An object representing a person who speaks.
*/
var Speaker = {
init: function(options, elem) {
// Mix in the passed in options with the default options
this.options = $.extend({},this.options,options);
// Save the element reference, both as a jQuery
// reference and a normal reference
this.elem = elem;
this.$elem = $(elem);
// Build the dom initial structure
this._build();
},
options: {
name: "No name"
},
_build: function(){
this.$elem.html('<h1>'+this.options.name+'</h1>');
},
speak: function(msg){
// You have direct access to the associated and cached jQuery element
this.$elem.append('<p>'+msg+'</p>');
}
};
I use an object literal here which puts me in the Prototypal Inheritance camp, I believe, but this is just an easily digestible pattern.
As you can see, there are easy-to-read, small functions, that have a clear purpose. In our use of this pattern, we call api type methods like speak() but not necessarily an internal method (like _build). You can hide your internal functions either by naming convention (not really hiding them), or by using something like the module pattern. In our simple example, I have just added an underscore to the beginning of the function to indicate that it's private.
Code that is organized like this is much easier to test and to change/read. This also allows you to change the way things function without changing the way that the Object api is used. For instance, we could change the speak method to alert the string instead of append it to the related element. We would have to change the internals of the speak function, but we could keep our call to it the same.
The bridge that we build is probably the most interesting part of this pattern. It's a different approach than many of the popular plugins take (slightly different than jquery ui), but it has a few really great benefits.
The most simple way to do this is by hand:
// Make sure Object.create is available in the browser (for our prototypal inheritance)
// Courtesy of Papa Crockford
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
(function($){
// Start a plugin
$.fn.speaker = function(options) {
// Don't act on absent elements -via Paul Irish's advice
if ( this.length ) {
return this.each(function(){
// Create a new speaker object via the Prototypal Object.create
var mySpeaker = Object.create(Speaker);
// Run the initialization function of the speaker
mySpeaker.init(options, this); // `this` refers to the element
// Save the instance of the speaker object in the element's data store
$.data(this, 'speaker', mySpeaker);
};
}
};
})(jQuery);
And that's it!
Now you have separated the creation of the plugin from the actual code itself. You are using the plugin to attach objects (with any inheritance patten) to dom elements and visa versa, but the plugin itself is just the connection and initialization code. This means that we could generalize this process further. I first saw this from Scott Gonzalez (of the jQuery UI team) and his code later became the 'widget factory' in jQuery UI. I prefer to not pass strings into my plugins in order to call functions, but it's a valid approach as some people would take issue with having to pull out the object each time they started with a dom element.
Here is some code that might get you started writing/using a 'bridge' function (bridge is what's found now in jQuery UI 1.8) that can help you attach your general code with a given plugin (since writing that same initialization plugin code multiple times would get old and defeat the whole DRY principle that our inheritance model has hopefully provided). This code is mostly courtesy of Scott Gonzalez because I couldn't think of a more stripped down elegant approach to this. I changed it to accept Objects instead of Constructor Functions because that works a little better with my example (prototypal inheritance). I also force it to call my init function in order to save myself an extra call. (This example shows Scott's use of this method along with John Resig's Simple-Inheritance implementation - also very cool.)
$.plugin = function(name, object) {
$.fn[name] = function(options) {
var args = Array.prototype.slice.call(arguments, 1);
return this.each(function() {
var instance = $.data(this, name);
if (instance) {
instance[options].apply(instance, args);
} else {
instance = $.data(this, name, Object.create(object).init(options, this));
}
});
};
};
// With the Speaker object, we could essentially do this:
$.plugin('speaker', Speaker);
// At this point we could do the following
$('#myDiv').speaker({name: "Alex"});
That's about all there is to it. I'd encourage you to pick some pattern for your development that isn't just inline chaining of jQuery function calls. This way of breaking up and organizing functionality in your code serves as a quick and easy jumping-off point for testing and modularity. It's much easier to test the individual functions of a modular object than it is to write tests for a single-line chain of jQuery calls.
Also, I do get some feedback along the lines of "well, my code is not a plugin" - "this isn't applicable to my code" - but I usually tend to disagree. The stigma that a jQuery plugin has to be for general consumption is flawed. I encourage you to use the plugin architecture if you are creating functionality based on a dom element selection. For instance, if you are adding an error notification system, it would be very easy to create a notification object that attaches to a div and has the methods required for notification directly attached to it, rather than having a function that merely hides and shows random dom elements.
I am doing a round up of performance on a lot of this inheritance usage and I should get to writing another entry on that soon, but from my early tests, using reasonable inheritance is generally not that expensive. If you are pushing the limits of CPUs and browser rendering, you might have to make some sacrifices, but for the general case, the instantiation hit of inherited objects is probably well worth your while.
I'd love to hear about the way you approach this problem.
February 25th, 2010 - 16:16
Alex, really well explained entry. The topic of inheritance is always a lot of fun (and particularly interesting in Javascript’s unique context). I happen to be a fan of the “new” keyword approach for implicit constructor usage; but, seeing this way is also very cool. I remember the first time I saw Crockford describe this and I had to re-read his create method like 10 times before I could visual what was actually going on (sometimes, for me, prototypal inheritance is not the easiest thing to visualize).
Also, I think this is the firs time I ever saw the core data() method used (not off a jQuery collection). I really like that! And it makes perfect sense in a plugin context where you might have a jQuery collection wrapping a given node.
February 25th, 2010 - 16:33
Yea, I guess I take it for granted that Javascripters like the Prototypal way of thinking. I really like it and think it offers a pattern that fits my javascript development. I can totally understand not liking it though. Object.create() just seems so easy!
As far as the $.data call – creds to Scott and Paul for pointing that out to me. It’s better for performance and for modularity!
February 25th, 2010 - 18:43
Very interesting approaches. I would have never thought of a prototypal inheritance pattern being wrapped in a jQuery plugin… I guess it has its uses!
I usually take the approach of setting my element through a “private” string like:
var Speaker = {
_elem: '#myDiv',
speak: function(msg){
$(this._elem).append('' + msg + '');
}
}
Hard-coding an element to a string like that I think is a little more-so of a global configuration though, maybe not particularly good for instances if your element is unique to an instance.
February 25th, 2010 - 19:01
Yea, the goal was so you could eventually do something like this:
$('ul#listOfSpeakers li').speaker({...}); // so there are a dynamic amount of li elements that get selected and connectedThat way it’s element neutral, just each instance contains a reference to it’s element. It more of a connection to an element, and less of an abstraction, I suppose, in that regard.
February 26th, 2010 - 15:25
Nice article, and I love your approach.
I bloged about similar but more complex solution some time before, but I guess that an simpler solution like your is more suitable to present inheritance to jQuery developers.
Regarding your concerns about inheritance performances, I would suggest a faster Object.create (2x faster):
(function(){
function F(){}
Object.create = function( o ) {
F.prototype = o;
return new F();
};
})();
February 26th, 2010 - 15:32
Thanks for the tip, that makes a lot of sense (no reason to re-allocate that function)! Of course, now we’ve taken something from “definitely fast enough” to “very definitely fast enough” – I want to meet the programmers that are instantiating millions of objects at once.
February 26th, 2010 - 17:23
@Robert,
That’s pretty slick.
February 26th, 2010 - 21:29
Funny this topic comes up as I work to write out my own take on inheritance in JavaScript. My post is not as fleshed out as I’d like (and nowhere near how detailed as Alex was) so I apologize but I’m eager to share what I do have:
http://blog.johngauthier.com/2010/02/26/prototyping-javascript-objects-functionally-using-jquery-and-json/
The $.declare() function I’ve created allows for direct inheritance from any existing prototyped class, or the creation of a base class. Have a look and please let me know what you think. With my lack of thorough documentation I’d almost recommend that you simply try to use the code on your own and toy with it; that may yield you a better understanding.
I’m in the middle of swapping out Joomla in favor of WordPress, too, so please don’t judge harshly…
February 26th, 2010 - 23:40
@John
That looks great man. It’s good to see other people caring about this kind of thing.
I’m not sure you’d agree, but it might be more readable to put the ‘inherited class’ first in your declare function. You can just do some type checking on the arguments object or something to figure out whats what when something extends undefined, but it might read a little more clearly. It reminds me of LowPro.
Also, you might check out dojo’s declare function. Has a bit of the same power you’ve wrapped as well. In fact, you’d be able to use your inheritance methodology with my bridge, without a hitch! Great work.
March 1st, 2010 - 16:52
I look at it more like PHP, and admittedly my jQuery background isn’t as strong so I’m not as familiar with convention. So you’re thinking that for jQuery/JavaScript the better approach would be this?
$.declare(objectParentClass, stringNewClass, jsonPropertiesAndFunctions);
Relatively minor change to be sure.
March 1st, 2010 - 17:04
@John
I wasn’t very clear in my description, this is what I might find to be the most readable:
$.declare(stringNewClass, objectParentClass, jsonPropertiesAndFunctions);
That way it kind of reads naturally.
Declare ‘newclass’ that is a ‘parent class’ with the new properties of ‘x y and z’.
That way you don’t have to search down to the bottom of the object literal to see what it inherits from.
Thats just nitpicking though, its the right direction for sure.
March 2nd, 2010 - 16:11
@Alex
“That way you don’t have to search down to the bottom of the object literal to see what it inherits from.”
For whatever reason that never really occurred to me; excellent point.
March 4th, 2010 - 18:00
That declare function looks a lot like Dojo’s declare:
http://dojotoolkit.org/reference-guide/dojo/declare.html
March 4th, 2010 - 20:18
How would you know? Did you write it or something?!?!?! :D
If you look closely, I may have mentioned that it reminded me of declare in my reply… yay dojo.
February 26th, 2010 - 23:21
Excellent article Alex! At a first glance, I thought I was clear, but I have few layman’s doubts in your article. May be, I’l write to you.
I’ve been using revealing module pattern to modularize my jQuery code. I’ve written a li’l article about it: http://www.novogeek.com/post/2009/10/28/Love-JavaScript-design-patterns-love-your-jQuery-code-even-more!.aspx
May be you folks can validate if my code can look even better.
February 26th, 2010 - 23:46
@Krishna
I am a big fan of the module pattern. I read your article (and have read most of those recommended articles/books you mention) and it’s a nice and concise roundup of modular javascript techniques. I intentionally didn’t use too much fancy stuff in this article just to keep the main point as the focus. I would encourage that anyone who used this pattern would actually use the module pattern (which I think I mentioned in the article) in order to expose only the api they want to. I don’t think the underscore prefixes go far enough to do real encapsulation/modulepatternstuff.
So I’d encourage you to mix the module pattern into the plugin bridge and see what kind of cool stuff you can do with it.
February 27th, 2010 - 08:45
I’m not sure I follow the second half of this article in how you can call your plugin’s without instantiating it directly. This is a very interesting read and has eliminated a jQuery chain link that I thought was essential.
I’m going to play with this and see if I can’t clean up my own JavaScript. Two paragraphs into this I thought Ben Nadel would like this. Sure enough he’s the first comment.
February 27th, 2010 - 11:21
This is a very fascinating approach. I would love to see you go further into solving a real world problem with this approach.
Perhaps something along the lines of: fetching data off a server; rendering that data in HTML; attaching additional plugins / functionality to those newly rendered elements; All without nesting plugins inside of plugins.
March 5th, 2010 - 06:39
Alex, great writeup. I’m implementing the object literal pattern in a mini-project I’m working on using your example as a template, and would like to hear your advice on using the “this” keyword vs. the object name inside functions. I ran into a situation where my “_run” method calls this code:
$(window).scroll( this._detectState );
This apparently changes the scope of “this” from the object to “window” inside _detectState(); Therefore, the only way I can refer back to my object is by calling “MyObject.myProperty”, instead of “this.myProperty”. Not a big deal, except I feel like this is a dirty approach, as now some of my methods are using “this” whereas others are using “MyObject”. How is this best handled? Normalize “MyObject” over “this” across all functions, or am I missing a big concept here?
You can see what I’m working with @ http://pastie.org/855492
Thanks!
March 5th, 2010 - 09:26
Hey Eric,
Yeah, so it’s not immediately obvious what’s going on here, since your code actually does make sense from the JavaScript side of things. BUT remember how awesome jQuery is and gives you the power to do things like this?
$(‘#id’).click(function(){ $(this).hide(); });
Well, if you look there, the `this` keyword references the DOM Element with the id of `id` – whereas in pure javascript, it should reference something like window, or whatever object is was instantiated in.
In other words – jQuery is messing with you. It’s changing the context to the element that you selected with the jQuery function. In this case, you pass in `window` – so your function gets run in that context thanks to jQuery.
The hard (not really) fix – a closure:
var that = this;
$(window).scroll(function(){ that._detectState(); });
Or the new hotness – the $.proxy method:
$(window).scroll($.proxy(this._detectState, this));
In dojo, this is the `hitch` function and in Prototype, it’s the `bind` function.
I didn’t run any of this, so hopefully its right…
March 11th, 2010 - 19:53
Like it,
I did a large jQuery application recently after doing a lot of small website and I must say , I fell short in “application design”..
I started it like a normal website and realized I was heading the wrong way. The application is not bad but I it would have been cool to test this pattern on it!
But I will make sure to test it next time.
April 1st, 2010 - 14:35
I may be doing something wrong but when calling a plugin multiple times ie.
$(‘.element’).speaker();
$(‘.element’).speaker(); //error
The second call errors with ‘cannot call method ‘apply’ on undefined’ Line 7 of your plugin bridge above.
rewriting like this made it work
if(instance)
instance.init(options,this)
else
…..
can you explain what this line does and why I may be getting an error?
April 1st, 2010 - 14:51
The bug is actually likely on a different line, that’s just the first place that something cares that the object doesn’t exist.
As far as why that’s happening, I’d have to see your implementation of it, but when I wrote this simple example, I didn’t intend for elements to be multiple speakers of the same object. Currently, the way the object bridge works is by looking at the plugin name. So by connecting two objects of the same plugin name to the element, there is no way to get both back. This is obviously just a limitation of this script, but it’s an important one. If you can’t figure out how to do that, but really need to get that done, you might try building two different bridges. Like so:
// instead of: $.plugin('speaker', Speaker); $('.elems').speaker(); $('.elems').speaker(); // define two different plugins, so they are "different types" and don't conflict $.plugin('speakerone', Speaker); $.plugin('speakertwo', Speaker); $('.elems').speakerone(); $('.elems').speakertwo();Just make sure you realize that you should only be calling the plugin is when you are actually creating and initializing the object. Otherwise, you should access it via the `$.data` method.
May 8th, 2010 - 10:51
Very cool stuff! It took me however a while to figure out how to make it work with your suggested $.plugin function.
The issue was that $(“#myDiv”).data() returned an empty object. To fix this the init function of Speaker must look like this:
init: function(options, elem) {
// Mix in the passed in options with the default options
this.options = $.extend({},this.options,options);
// Save the element reference, both as a jQuery
// reference and a normal reference
this.elem = elem;
this.$elem = $(elem);
// Build the dom initial structure
this._build();
return this;
},
Note the added “return this” at the end of the function :-)
July 1st, 2010 - 16:12
Hey Alex, thanks for the wonderful post. :)
I’m trying to apply this inheritance pattern to my code, specifically Scott Gonzalez’ bridge. In the code sample you link to (http://pastie.org/517177), he never calls init() explicitly. Why is it necessary in your modification of his code?
July 1st, 2010 - 16:15
He’s using it in conjunction with John Resig’s ‘simple-inheritance’ which automatically calls the init function. I would encourage that method, but I was trying to stay agnostic to specific patterns.
July 18th, 2010 - 13:06
Alex, thanks for this article. I’m somewhat new to javascript and have been trying to figure out strategies for organizing my code. I’m having a good time applying these principles.
I could be missing something, but I believe there is a small error in your example code. Specifically, I think that you need to “return this” in Speaker.init. Otherwise, $.data(this,name, Object.create…init) in the generalized bridge will always just store null.
Anyway, thanks again!
July 24th, 2010 - 00:53
Alex,
Love your article here, and I think I like your pattern better than the jqueryui one. Can you offer any more explanation of how you would integrate the module pattern here, or point to a good primer or some good books? Really hitting this organization/pattern/DRY stuff hard lately.