Uncategorized

Using Namespaces in Javascript

February 8, 2007

author:

Using Namespaces in Javascript

As AJAX and Javascript widgets get more popular, it is not unusual to see Javascript from multiple parties running on the same page. This greatly increases the chances of collisions in variable and function names. For instance, two unrelated scripts might define the function “modifySomething()”. In this case, the last definition of “modifySomething()” on the page will be the one called. This is an invitation to disaster.

One way to prevent this is to practice defensive Javascript coding through the use of namespaces. In .Net and Java, the use of namespaces clearly delineates classes and prevents collisions. While Javascript does not have a built-in mechanism for using namespaces, it is relatively easy to implement them. In fact, just about every library such as Dojo Toolkit, Yahoo UI and ASP.Net AJAX provides a mechanism for registering and using namespaces in Javascript. This is fine if you are using one of the libraries, but if you are not, then how do you go about creating namespaces in your Javascript code. Read on.

Let’s create a simple “Cube” class with properties of Width, Height, Depth and methods grow() and shrink(). This class must reside in the “Speerio.Web.Solids” namespace.

If we try something like this: 

Speerio.Web.Solids.Cube = function(width, height, depth)
{
      this.width = width;
      this.height = height;
      this.depth = depth;
}

…we get an error. This is because Javascript expects to find an object “Speerio”, with a child object “Web”, which has a child object “Solids”. To make this work, we will first need to define a way to tell Javascript that the “Speerio.Web.Solids” hierarchy exists. We can do this by creating a function to create the hierarchy like this:

function $register(ns)
{
    var segs = ns.split(".");
    var namespace = window;
    for(var s = 0; s < segs.length; s++)
    {
        var seg = segs[s];
        if (typeof(namespace[seg]) == "undefined")
            namespace[seg] = new Object();
            
        namespace = namespace[seg];
    }
}

This function adds our namespace as a hierarchy of objects that are children of the top-level “window” object. It only works if the object has not already been defined, so it’s OK to register the same or similar namespaces multiple times. Now, it’s a simple matter of calling the function:

$register(“Speerio.Web.Solids”);

Once the namespace is registered, we can use it in our code as we would any other object. Since we are talking about defensive coding, let’s go further and define the “Cube” class.

Speerio.Web.Solids.Cube = function(width, height, depth)
{
       this.__width = width;
       this.__height = height;
       this.__depth = depth;
}
 
Speerio.Web.Solids.Cube.prototype =
{
       shrink : $Speerio_Web_Solids_Cube_Shrink,
       grow : $Speerio_Web_Solids_Cube_Grow,
       getWidth : $Speerio_Web_Solids_Cube_GetWidth,
       setWidth : $Speerio_Web_Solids_Cube_SetWidth
}

We start by defining the Cube class whose constructor takes three parameters — width, height and depth. In the definition of the class, these parameters are used to initialize properties __width, __height and __depth respectively. Why the underscores you ask? Mainly to discourage them from being directly modified. Javascript does not provide a set/get mechanism so to protect properties from being set directly, a small layer of obfuscation is necessary. It is not fool-proof…anyone studying your code will see this right away. However, it should be obvious that the intent is to protect the integrity of the data and prevent it from being modified directly.

Next, we define the various methods for the Cube class. For each method, the “public” method name is clear and simple. The actual method that does the work has a longer name. I used the following convention:

  • prefix all class methods with $
  • append the namespace and class name, replacing periods with underscores
  • append the name of the method, prefixed with “Get” or “Set” if the method is intended to be a property getter/setter

Now, we can define the actual methods:

function $Speerio_Web_Solids_Cube_Shrink()
{
    if ((this.__width > 1) && (this.__height > 1) && (this.__depth > 1))
    {
        this.__width--;
        this.__height--;
        this.__depth--;
    }
}
 
function $Speerio_Web_Solids_Cube_Grow()
{
    this.__width++;
    this.__height++;
    this.__depth++;
}
 
function $Speerio_Web_Solids_Cube_GetWidth()
{
    return(this.__width);
}
 
function $Speerio_Web_Solids_Cube_SetWidth(w)
{
    if (w > 0)
       this.__width = w;
}

And finally, some code to test the class:

var cube = new Speerio.Web.Solids.Cube(10, 10, 10);
cube.grow();
cube.grow();
cube.shrink();
alert("The cube width should be 11; the actual value is " + cube.getWidth());
cube.setWidth(100);
alert("The cube width should be 100; the actual value is " + cube.getWidth());

The above namespace-based class definition protects your code when it is running on a page where code from other parties is also executing. In addition the code is readable and likely easy to manage, even if months have elapsed since you last took a look at it. There may be a small performance hit the first time the script file is downloaded to the user’s browser due to the verbosity, but I’ll take verbose code that works over concise code that breaks the page any day.

Co-founder/CTO WhenHub; co-founder DNN Software; founder Edaptable; educator; Open Source proponent; Microsoft MVP; tech geek; creative thinker; husband; dad. Personal blog: http://www.kalyani.com. Twitter: @techbubble
Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.