PrototypeJS extension: namespaces for JavaScript

Namespaces are an extremely useful tool when working with numerous classes, functions or even objects in many programming languages. They allow the developer to group these entities in an intuitive way to facilitate readability.

More importantly, namespaces are a mechanism which help to avoid clashing occurrences of unrelated objects which share the same name. This can easily happen when utilizing sources that were developed by separate parties.

A while back I wrote a utility method to ease the support of namespaces within JavaScript. This utility method uses features from the PrototypeJS framework.

In JavaScript a function could be placed within a namespace called “First” using the following:

// If namespace has not yet been defined, define it.
if (!First) {
  First = {};
}
 
// Add function "foo" to the namespace "First".
First.foo = function() {
  alert("Hello World #1");
}

Whilst this is fairly straightforward, it is necessary to test and define the required namespace every time scripts need to add functionality. Things get even more complicated when namespaces are nested within one another:

// Make sure that "First.Second.Third" namespace is defined.
if (!First) {
  First = {};
}
if (!First.Second) {
  First.Second = {};
}
if (!First.Second.Third) {
  First.Second.Third = {};
}
 
// Add function "foo" to "First.Second.Third" namespace.
First.Second.Third.foo = function() {
  alert("Hello World #2");
}

JavaScript does not include any keywords that are specifically aimed towards tackling this problem. I am a massive fan of the PrototypeJS framework because it brings in a lot of additional object oriented concepts such as classes and inheritance.

So, I wrote a simple function to be used in conjunction with the PrototypeJS framework (note that this function will not work independently). This utility function merely simplifies the above two examples to the following:

$namespace("First", {
  foo: function() {
    alert("Hello World #1");
  }
});
 
$namespace("First.Second.Third", {
  foo: function() {
    alert("Hello World #2");
  }
});

These functions can then be invoked as follows:

First.foo();
First.Second.Third.foo();

Separate scripts can then further extend a namespace using exactly the same approach:

$namespace("First.Second.Third", {
  bar: function() {
    alert("Hello World #3");
  }
});
 
First.foo();
First.Second.Third.foo();
First.Second.Third.bar();

Here is my implementation of this functionality, please feel free to use it in your own projects under the usual BSD license. You can acquire the latest version of the PrototypeJS framework from http://prototypejs.org/download.

/*!
 * (c) 2010-2011 Rotorz Limited. All rights reserved.
 * License: BSD
 * Author:  Lea Hayes
 * Website: http://leahayes.co.uk
*/
var $global = window;
 
function $namespace(name, extension) {
  var namespaces = name.split('.');
  var parentNS = $global;
  namespaces.each(function(nsID) {
    var ns = parentNS[nsID];
    if (ns === undefined || ns === null) {
      parentNS[nsID] = (ns = {});
    }
    parentNS = ns;
  });
  if (extension) { // Extend namespace?
    Object.extend(parentNS, extension);
  }
  return parentNS;
}