Simple JavaScript Namespaces
“Namespaces are one honking great idea — let's do more of those!” - Tim Peters, “The Zen of Python”
After a few years of mostly server-side development I'm getting back into JavaScript, and for the first time I feel like I'm approaching it as an actual engineering challenge rather than a bunch of quick hacks. As our JS code base is growing I'm breaking things up into namespaces to keep things manageable.
Though JavaScript has no built-in notion of "modules" like many other languages you can use objects to create namespaces, which in their simplest form would look something like:
util = { my_func: function() { alert('my_func'); } }; util.my_func();
However, creating nested namespaces like "myapp.util.text" gets a bit ugly with that approach. I liked the basic API of Namespace.js, though I didn't want any of the additional features like remote loading, so I figured I could make something much simpler and smaller.
You can first "declare" a namespace and then assign attributes like:
Namespace('myapp.ui'); myapp.ui.ToggleButton = function() { // ... };
Or pass in the attributes to include in that namespace:
Namespace('myapp.util.text', { some_func: function() { } });
Here's the code:
function Namespace(name, attributes) { var parts = name.split('.'), ns = window, i = 0; // find the deepest part of the namespace // that is already defined for(; i < parts.length && parts[i] in ns; i++) ns = ns[parts[i]]; // initialize any remaining parts of the namespace for(; i < parts.length; i++) ns = ns[parts[i]] = {}; // copy the attributes into the namespace for (var attr in attributes) ns[attr] = attributes[attr]; }
This is of course much smaller than the 16kb of Namespace.js, so as an additional challenge I decided see if I could compact it to fit the 140 character limit of a Twitter status message :) (Note: the Twitter version used jQuery's $.extend function to copy the attributes into the namespace which I later replaced with the framework-independent version above.)
I'll follow up later with some tricks I've been thinking about to "import" stuff from other namespaces.