January 2013
Javascript can be a difficult language to grasp. It lacks common concepts like modules and classes that are present in many other languages. New developers starting with Javascript find it hard to organize code in a proper way. There are simply too many ways to code tasks in Javascript, and every framework seems to define their own ways. It is unfortunate that the language does not provide native constructs for basic engineering tasks. Fortunately there are patterns available and frameworks have matured a lot since the early days.
Since it seems common for every other web developer to publish his own boilerplates, I'm following the crowd too ;) In this blog post I share two boilerplates that I have been using myself in developing web apps. The first is a simple module pattern that groups a number of functions into the same namespace and provides data encapsulation. The second is a pattern to build jQuery plugins. There is nothing really major here that hasn't already seen the light elsewhere; these are just my favorite ways to organize code in Javascript.
Most likely you knew this already: One of the worst parts of Javascript is the reliance on a single global namespace. Every function of a script is imported to the global namespace (bound to the "window" object). If you have a lot of scripts, you can end up with name collisions with all kinds of hard to debug surprises. Scripts can't have functions with the same name. This is bad. Every module should really exist in a private namespace. Data encapsulation and privacy are the first lessons learned at school, right?
While Javascript does not have a language level construct for constructing
modules, it does provide a way to group functions and data in a private
namespace. By using Javascript's most powerful feature
,
closures , it is possible to
create an anonymous function, invoke it immediately and create a closure of
functions and data. At first the construct looks awkward but it does the job.
This pattern is called the module
pattern.
There are actually many variances of module patterns in the net. My preferred version is the The Revealing Module Pattern. It is simple and easy for the eyes:
// mymodule.js - a naive example module with 2 public functions,
// 1 private function and 1 private variable
var MYMODULE = (function () {
// variables and functions private unless attached to API below
// 'this' refers to global window
// private array
var array = [];
// add a number into array
function add(a) {
log("add "+a);
array.push(a);
}
// return copy of the array
function get_array() {
log("copy_array");
return array.slice();
}
// a private debug function
function log(msg) {
console.debug(msg);
}
// define the public API
var API = {};
API.add = add;
API.get_array = get_array;
return API;
}());
The above module is used like this:
MYMODULE.add(1);
MYMODULE.add(3);
var arr = MYMODULE.get_array();
The boilerplate has the following treats:
The added benefit of using the module pattern comes with minification:
the
private function and variable names of the module get obfuscated during
minification process.
Note that this pattern creates a single global module; this is not an OOP pattern for creating objects. OOP in Javascript is a controversial topic with too many opinions :) A quick simplified intro: To create an object, the module pattern can be slightly modified to behave as a construction function, and the function is then invoked together with the new keyword. I'm using this pattern to create an object in the below jQuery boilerplate.
I remember the first time I wanted to create a jQuery plugin. The ride was not all smooth and fast; it took a while to figure out which one of the many jquery tutorials to learn. The official plugin documentation left questions unanswered: how to maintain plugin state, how to take care of event callbacks and how to provide an API for the plugin?
After reading a few blogs and lots of source code, I eventually found
practices in creating a decent jQuery plugin. The boilerplate below is a
typical construction: it creates a Javascript object containing the plugin
logic, API and state, and then ties the object to each DOM element in the
jQuery selector. The object is cached in the element's .data()
where it can
be accessed after creation. The object defines its API similarly as in my
module pattern above.
;(function($) {
// wrap code within anonymous function: a private namespace
// replace 'MyPlugin' and 'myplugin' below in your own plugin...
// constructor function for the logical object bound to a
// single DOM element
function MyPlugin(elem, options) {
// remember this object as self
var self = this;
// remember the DOM element that this object is bound to
self.$elem = $(elem);
// default options
var defaults = {
msg: "You clicked me!"
};
// mix in the passed-in options with the default options
self.options = $.extend({}, defaults, options);
// just some private data
self.count = 1;
init();
// initialize this plugin
function init() {
// set click handler
self.$elem.click(click_handler);
}
// private click handler
function click_handler(event) {
alert(self.options.msg + " " + self.count);
self.count += 1;
}
// public method to change msg
function change_msg(msg) {
self.options.msg = msg;
}
// define the public API
var API = {};
API.change_msg = change_msg;
return API;
}
// attach the plugin to jquery namespace
$.fn.myplugin = function(options) {
return this.each(function() {
// prevent multiple instantiation
if (!$(this).data('myplugin'))
$(this).data('myplugin', new MyPlugin(this, options));
});
};
})(jQuery);
The plugin is used like this:
var options = {msg : "Click!"};
$('#elem').myplugin(options);
// get the API to the plugin object
var api = $('#elem').data('myplugin');
api.change_msg("Hello there!");
If you feel brave and want to read more about different jQuery plugins, go ahead and read Addy Osmani's exhaustive list of Essential jQuery patterns.
If you have a small web app with less Javascript, you can concatenate and minimize all the modules in the production setup into a single script to be loaded once during initial page load. Most likely there would be no noticeable advantage in loading small Javascript modules on demand. (Each HTTP request has latency anyway.) You internally organize modules into separate files but externally serve a single file.
However, in a large web application with several thousand lines of Javascript, it may become useful to load modules on demand as they are being used. With on demand loading the app loads faster, initially consumes less resources and generally feels quicker. Speed is essential in great user experiences.
RequireJS may be the most comprehensive solution for dynamic loading of resources in Javascript and declaring dependencies between modules. Here I'm introducing another solution that I like for its simplicity.
HeadJS is a small Javascript library packed with combination of features for dynamic loading of scripts and CSS, browser feature detection and support for responsive design. If you only care about the dynamic loading, the size is only 1.9K (minified and gzipped).
Below is a simplified example of HeadJS in action. In the document, only the HeadJS script is declared as a regular script. Once loaded, HeadJS fetches jquery and mymod1.js asynchronously. head.ready() will get fired once the 2 modules are loaded and document DOM is ready.
Later in the app, when the user invokes a feature that is implemented in mymod2.js, the app dynamically loads mymod2.js and mymod2.css if they are not already loaded and then continues to invoke the init() function in the mymod2.js.
<html>
<head>
<title>testing headjs</title>
<script src="head.load.min.js"></script>
</head>
<body>
...
</body>
<script type="text/javascript">
head.ready(function() {
// called when jquery + mymod1.js loaded and doc ready
// init mymod1.js
MYMOD1.init();
});
head.js("http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js",
"mymod1.js");
</script>
<html>
// somewhere in mymod1.js:
// another module required, load mymod2.js and it's css file
head.js("mymod2.js", "mymod2.css", function(){
MYMOD2.init();
});
I put together a small demo that demonstrates the boilerplates and dynamic loading introduced above. Initially the demo loads jquery and main.js modules, and on demand loads module2.js, module2.css and jquery-plugin.js.
See demo online or download demo.
To observe dynamic loading with Chrome, you could install my Chrome extension Quick source viewer (screenshot on right). It shows page sources with syntax colorization and beautification, and has other features. In the extension, dynamically loaded scripts are labeled as "INJECTED".
Thanks for reading.
Back