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.