Widget JavaScript, the Un-series: Part 0 (Namespacing and the Module Pattern)
13 May 2008 · Estimated reading time: 5 minutes
I’m not big on series of blog posts. Others have done it successfully, but personally I’ve promised this kind of thing before and not delivered. So, I’m not making any promises that this series will get past Part 0, but please know I have the best of intentions. If all goes as hoped, over the next however-many posts I will provide a few useful JavaScript code snippets that Dashboard widget authors can take and easily adapt to their own needs. This is based on my experience authoring nearly 20 widgets over the last 3 years. As you can imagine, some patterns have emerged. In this pre-series post, I will discuss a couple of concepts important to understanding my examples (you know, if I get around to posting them): namespacing and the module pattern.
Namespacing
You namespace your JavaScript, right? Right?!
Just because Prototype doesn’t do it doesn’t mean you shouldn’t. Better to follow the example of jQuery, YUI, and Dojo and put your JavaScript in a tidy little top-level object so it has less chance of stomping on or getting stomped on by other scripts. I won’t name names, but I recently worked on a site where we were told to include 3rd party ad serving code that put the cleverly named function random()
in the global namespace. I’m surprised that’s not used as example #1 in the dictionary for the word “naive.”
Now that I’ve ridiculed you into submission, I’m going to say something you might consider a bit contradictory. In widgets, you don’t have to be so strict about namespacing. There, I’ve said it. Sue me. But first, let me explain.
Unlike the WWW (Wild West Web), where you’re not always in control of all the JavaScript on your pages, in a widget, the environment is more controlled, so it’s easier to know what’s going on. So, rather than putting all of your JavaScript in one namespace (like I myself have done in all my [to-date] published widgets, again with the contradictions, sheesh!), I recommend grouping like functionality into namespaces.
For example, I plan to talk about (though I make no promises, you understand) preferences and version checking. Each of these could go in their own namespace. You know, like PREFS
and, oh, I don’t know, maybe VERSION
.
There’s nothing magical about this from a coding perspective. Here’s a simple example:
var MYNAMESPACE = {}; MYNAMESPACE.getFunky = function () { // do funky stuff }; MYNAMESPACE.getFunky();
Tidy. Orderly. Encapsulated.
Module Pattern
The module pattern is a technique for organizing large JavaScripts into public and private members. It was popularized by Douglas Crockford and has been blogged about (and criticized) all over the flipping shop.
One of the important concepts you need to understand to “get” the module pattern is closures. Go read this example-laden overview of closures as they are implemented in JavaScript and come back. I’ll wait.
My use of the module pattern is pretty faithful to the original. The purpose of it, for me, is to be able to create both public and private variables and methods in tight, little, namespaced objects. Here’s an example.
var MYOBJ; MYOBJ = (function () {// private variable var _rgxp; _rgxp = /^abc$/i; // private method var _isMatch; _isMatch = function (str) { return _rgxp.test(str); }; // public method return { ask: function () { var input; input = prompt('What are the first 3 letters \ of the alphabet?'); (_isMatch(input))? alert('Correct!') : \ alert('Wrong!'); } };
})();
MYOBJ.ask();
As I said above, this has the advantage of being tidy and encapsulated. I can also run this with confidence that my regular expression (because it’s assigned to a private variable) hasn’t been stomped. The example is contrived, but hopefully you get the idea.
Bonus!
As a reward to myself for finishing each of the posts in this “un-series,” I plan to (again, no promises!) include at the end a little “bonus” code I use to make my widget-building life a little easier. Enjoy!
If you don’t currently localize your widgets, you should. It’s pretty easy and it not only gives you a wider audience for your work, it makes your non-native language users feel all warm and fuzzy.
The following function is based on one generated by Dashcode, Apple’s excellent Dashboard development IDE. Usage is simple. You tell your string you want it localized and it takes care of looking up the string in the localizedStrings
array from the proper localized file, and replacing it out.
String.prototype.localize = function () { try { var string = localizedStrings[this] || this; } catch (e) {} return string; } var localString = 'My string'.localize();
In my day job, we use the Symfony PHP framework. Symfony creates a function for localizing strings: __
(That’s 2 underscores, if you’re wondering.)
Being used to the pattern __('My string')
, I decided to make it so I could call my localization String method in the same way. It’s simple, really.
__ = function (str) { return str.localize(); } var localString = __('My string');
Conclusion
OK, that’s it. I hoped you enjoyed this pre-installment of my un-series. I hope to post the next one, real soon now…