There was a time when just the mention of "jQuery" was enough to cause my face to wrinkle up. This was largely due to having been weened onto the Mootools javascript framework before all else. I also can't deny the fact that I have a natural tendency to avoid the "flyboy answer" to anything. Is jQuery a great tool? Without a doubt. Its also the only framework that seems to actively promote itself, often times through misleading and inaccurate statistics, which attracts masses of flyboys, making it--you guessed it--the "flyboy answer."
However, there are many instances where we won't always be able to use our preferred tools of the trade. This fact means its especially important for any javascript developer to invest time in learning several tools and adapt solutions that make the alternatives more familiar to work with. In this post we'll compare the normative jQuery plugin pattern (as presented by jQuery) to one loosely modeled after the Mootools Class constructor to find a simple and comfortable median between the two in the context of jQuery. The result will be an object oriented plugin that is reusable and allows you to maintain state without having to do elaborate element storage.
Before we look at this example, I think its important to note that I by no means consider this pattern bad. The main disadvantage to this pattern in my eyes is a lack of separation, which results in less than desirable efficiency and modularity. Consider the following:
(function($){
var myPlugin = $.fn.myPlugin = function(options) {
var opts = $.extend({}, myPlugin.defaults, options),
privateVariable1,
privateVariable2,
privateVariable3;
function privateFunction() {
// do stuff
}
// more private functions
return this.each(function() {
$(this).doMagicalThings();
privateFunction($(this));
// and so on
});
};
myPlugin.defaults = {
option1: null,
options2: null,
speed: "fast"
};
})(jQuery);
jQuery(function() {
$(".selector").myPlugin(/*options object*/)
});
What's so terrible about this? For starters, maintaining state is difficult--or at the very least, ugly. jQuery suggests the use of $.data to store various state-related information onto the elements returned from the selector that your plugin is manipulating. For simple plugins this may seem adequate, but in creating larger and more complex plugins this could quickly get out of hand.
Two words - code legibility. The function body for a remotely complex plugin will quickly fill up with a multitude of private functions and variables, all seemingly unrelated. There's nothing I hate more than having to scroll up and down through code resembling something like this as I attempt to follow the flow of the application.
Efficiency and modularity are also lacking if not nonexistent in a pattern like this. Because a plugin modeled in this fashion returns no reusable object, one would find themselves continually making the same calls over and over again with the same initialization code executing every time. For example, lets say we want to use something like setTimeout or setInterval to periodically update the tweets on the page every 60 seconds in a twitter plugin. Whether this functionality is implemented within the plugin or outside of it, its likely the same initialization code will get performed over and over again. Things like compiling our tweet template, parsing options, and forming the proper URL for our twitter request will happen multiple times when they should only happen once.
One quirk in all of this is that jQuery takes a relatively hands off approach in providing native constructors for creating things like plugins. These decisions are completely in the hands of the developer. Such freedom can be great, but something can also be said for the reassurance an author gets when they see a strong internal construct for creating modular and integrated code--so strong that the framework itself embraces it.
This pattern is modeled after the approach that Mootools provides through the Class constructor. This is a very paired down version, but also one that I find myself using whenever I need to make some quick and dirty plugins in jQuery. If you desire more modularity and options than this can provide, I'd suggest checking out a more complete solution like base2 or use a framework such as Mootools or Prototype that include native constructors for creating your own "classes." On with the example!
(function($) {
$.myPlugin = (function() {
var returned = function() {
/* the constructor function -
when a new instance of this object is created
it will run immediately, passing any arguments
to the initialize method of the function's prototype
*/
return this.initialize.apply(this, arguments);
};
returned.prototype = {
defaults: {
key1: "value 1",
key2: "value 2",
key3: "value 3",
},
initialize: function(options) {
var opts = this.opts = $.extend({}, this.defaults, options);
// perform other initialization code
},
pluginMethod: function() {
// do stuff
}
};
function privateFunction() {
// do stuff
}
return returned;
})();
})(jQuery);
jQuery(function() {
var myPluginInstance = new $.myPlugin(/*options object*/);
myPluginInstance.pluginMethod();
});
And there you have it! Nothing fancy, but if you're looking to write jQuery plugins in a more object-oriented manner this is definitely a useful technique. If you have any approaches for achieving a similar effect I'd love to see them.
Comments have been closed for this post.