Friday, June 6th, 2008

An Easy Way to Implement Namespaces in JavaScript

By Alex Melman

(Object-Oriented JavaScript Series)

Namespaces are a great way to uniquely distinguish objects from different projects. Unfortunately, JavaScript does not have native support for namespaces, but we can approximate it, by putting our objects inside other empty objects.

For example, to create a namespace called arc90.components, we would first define arc90 as an empty object:

arc90 = {}

If an object called arc90 already exists, we don’t want to erase it; so we will check for it first, then create an empty object only if the arc90 object doesn’t already exist. We can do that like so:

if (typeof(arc90) == "undefined")
arc90 = {}

The type of operator returns the type of an object as a string. If the object does not exist at all, a value of “undefined” will be returned. This is what we are checking for:

Now that arc90 is defined as an object, we can go ahead and define the next level of the namespace, arc90.components. We basically repeat what did for the arc90 part of the namespace:

if (typeof(arc90.components) == "undefined")
arc90.components = {}

By now, you must be thinking, “Boy, we’re repeating a lot of code here. There must be an easier way.” Well, don’t worry, there is. There are two options. You can use the YUI Library, which already contains a namespace function, or we can create a simple namespace function ourselves. Since I don’t want my tip to consist of just a link to Yahoo!, I will do things the long way and show you how to create a namespace function.

The most important part of the function is the use of the eval operator. This lets you pass in JavaScript code as text, allowing you to dynamically create object names. This is important, because normally, object names must be hard-coded, which would prevent us from creating new objects dynamically, if not for the eval operator.

Now, we will create a function, which will create a namespace object out of the string you pass in. For example, calling:

createNamespace("arc90.components");

will create an object called arc90.components. It also returns the object that was created, so that you can create an alias. For example, calling the function this way:

var alias = createNamespace("arc90.components");

will create the namespace object and set alias to reference the same value. Now, if we were to define a new object called Checkbox within the namespace, we can either use the fully qualified name, like so:

arc90.components.Checkbox = function() {}

or we can use the alias:

alias.Checkbox = function() {}

You can use either the fully qualified namespace or the alias to reference the same objects. The only thing you must be aware of is that you cannot give your alias the same name as any part of the namespace. For example, if you have a namespace called arc90.components, you cannot name your alias arc90, or components. This will overwrite the object in the original namespace.

Now, let’s create the createNamespace function:

function createNamespace(ns)
{
// First split the namespace string separating each level of the namespace object.
var splitNs = type.split(".");
// Define a string, which will hold the name of the object we are currently working with.  Initialize to the first part.
var builtNs = splitNs[0];
for (i = 0, i  0) ? ("." + splitType[i]) : "";
// Check if the object we want to add exists, and add a new empty object if it doesnt.
eval(builtNs + " = typeof(" + builtNs + ") =='undefined' ? {} : " + builtNs + "; ");
}
return eval(ns);    // Return the namespace as an object.
}

The above code first splits the namespace string into parts, so that a namespace called arc90.components will be split into two strings, arc90, and components. The function then loops, adding the next string to the first as it goes. On the first iteration, we have only arc90, which will then be created as an object by the line:

eval(builtNs + " = typeof(" + builtNs + ") =='undefined' ? {} : " + builtNs + "; ");

This is essentially the same code we wrote at the beginning, rewritten using a one-line ternary operator, and wrapped in an eval statement. After the eval statement runs, the code generated would look like this (on the second iteration):

arc90.components = typeof(arc90.components) == 'undefined' ? {} : arc90.components;

So, there we have it; a function to create JavaScript namespaces. Enjoy.

5 Responses

  1. Josh W said:

    You have a typo:
    for (i = 0, i 0) ? (“.” + splitNs[i]) : “”;
    // Check if the object we want to add exists, and add a new empty object if it doesnt.
    eval(builtNs + ” = typeof(” + builtNs + “) ==’undefined’ ? {} : ” + builtNs + “; “);
    }
    return eval(ns); // Return the namespace as an object.
    }
    You also might be able to use “window” instead of “eval”, as eval can but unsafe.
    function createNamespace(ns)
    {
    // First split the namespace string separating each level of the namespace object.
    var splitNs = ns.split(“.”);
    // Define a string, which will hold the name of the object we are currently working with. Initialize to the first part to the current window.
    var i, base = window;
    for (i = 0; i

  2. Josh W said:

    // Let’s try that “for” again.
    function createNamespace(ns)
    {
    // First split the namespace string separating each level of the namespace object.
    var splitNs = ns.split(“.”);
    // Define a string, which will hold the name of the object we are currently working with. Initialize to the first part.
    var builtNs = splitNs[0];
    var i, base = window;
    for (i = 0; i < splitNs.length; i++)
    {
    if (typeof(base[ splitNs[i] ]) == “undefined”) base[ splitNs[i] ] = {};
    base = base[ splitNs[i] ];
    }
    return base; // Return the namespace as an object.
    }

  3. Mazharkhan said:

    I got something and something not.
    you give only 50% guidance. if you put one example with every blog.

  4. Alex Melman said:

    Thanks for the comments. To Mazharkhan, I actually do have an example of how to use the function, but I realize that I sort of buried it in the middle. Basically, you use the function as such:
    createNamespace(“arc90.components”);
    This creates the namespace, so now you can define functions and classes such as:
    arc90.components.CheckBox = {};
    The advantage of using the function is that if you don’t, you will have to define each level of the namespace separately, like this:
    var arc90 = {};
    var arc90.components = {};
    In addition, you would have to check to see if those objects already exist. Otherwise you will overwrite them with blank objects, which is not what you want to do when defining a namespace.
    As for the first comment, I promise to address it soon.

  5. Timothy Stone said:

    Hmmm… concerned about that use of `eval’ … you might want to consider refactoring it. Take a look at the YAHOO object itself for an example with leveraging `eval’.

Leave a Comment