Click here to Skip to main content
15,885,141 members
Articles / Programming Languages / Javascript

JavaScript namespacing

Rate me:
Please Sign up or sign in to vote.
4.33/5 (9 votes)
28 Mar 2013CPOL3 min read 29.6K   25   9
Creating namespaces through a function.

Introduction

Anyone that comes from a C#, Java background knows the importance of namespaces. It's the primary way to keep your code organized. JavaScript doesn't support namespaces, or does it?

Object nesting 

JavaScript is a dynamic language. You can create objects on the fly, and objects can contain other objects. This concept will allow for creating a structure of prototypes that mimic namespacing.

Let's look at the mammal, cat and dog example

JavaScript
var Animal=function()   {
    //we don't know yet
    this.numberOfLegs=null;
    this.sound=null;
    return this;
}
Animal.prototype.getNumberOfLegs=function() {
    return this.numberOfLegs;
}

Animal.prototype.makeSound=function() {
   alert(this.sound);
}

var Mammal=function()   {
    //all mammals have for legs;
    this.numberOfLegs=4;
    return this;
    }
Mammal.prototype=new Animal();

var Dog=function()  {
    this.sound="Woef";
}
Dog.prototype=new Mammal();

var Cat=function()  {
    this.sound="Miauw";
    return this;
}
Cat.prototype=new Mammal();

var Tiger=function()    {
    this.sound="Wroaar";
    return this;
}
Tiger.prototype=new Mammal();

var Leopard=function()    {
    this.sound="Grrrr";
    return this;
}
Leopard.prototype=new Mammal();

This is great. We could create all the mammals and we could make a base class for the birds etc... But what if we also needed to keep a list of IOS names. To list apples IOS's we'd need Tiger and Leopard.

And next to that let's consider Animal to be a class you shouldn't use directly. I tend call such classes Base. But with no namespace I can have just one base.

All in all we'd like to create our animals in the Animals namespace. Allowing for an IOS namespace that also has Tiger & Leopard and a Base class. The way we trick JS into mimicking namespaces is to create nested objects. In which we place other objects.

JavaScript
//Create the Animals namespace

if(typeof Animals=='undefined')  {
    window["Animals"]={};   
}

Animals.Base=function()   {
    //we don't know yet
    this.numberOfLegs=null;
    this.sound=null;
    return this;
}
Animals.Base.prototype.getNumberOfLegs=function() {
    return this.numberOfLegs;
}

Animals.Base.prototype.makeSound=function() {
   alert(this.sound);
}

Animals.Mammal=function()   {
    //all mammals have for legs;
    this.numberOfLegs=4;
    return this;
    }
Animals.Mammal.prototype=new Animals.Base();

Animals.Dog=function()  {
    this.sound="Woef";
    return this;
}
Animals.Dog.prototype=new Mammal();

//...etc

Notice the omission of 'var'. What we are doing here is add everything to the global namespace. To some this is considered a no-no, but it is exactly what jQuery, ExtJs, YUI and prototype do. The truth of the matter is, if you place all your classes and even functions in a single namespace, say your products name, then you'll actually prevent polluting the global namespace.

On top of that I tend to wrap all the code in a .js file inside an anonymous function. That way, you can have 'global' variables that are only available inside that source, and they won't pollute the global namespace.

JavaScript
(function() {
    //Create OurProduct namespace
    
    if(typeof OurProduct=='undefined')  {
        window["OurProduct"]={};   
    }
    
    var someVariableAvailableToAllClassesWithinThisFunctionButNotOutside="Hello";
    
    //Create the Animals namespace inside the OurProduct namespace
    
    if(typeof OurProduct.Animals=='undefined')  {
        window["OurProduct"]["Animals"]={};   
    }
    
    OurProduct.Animals.Base=function()   {
        //we don't know yet
        this.numberOfLegs=null;
        this.sound=null;
        return this;
    }
    .......
})();
//Note the () at the end. If you omit that this code will never be run.

Register Namespace

Namespacing this way is actually nothing more than creating nested objects. And since window itself is an object you can actually create objects directly into it. But if we would like to create an object in a non-existent  nested namespace, we'll need to create that first.

JavaScript
MyProduct.Objects.Person=function() {
    //This will fail, because MyProduct.Objects doesn't yet exist.
}

We would like to have a function like NameSpace.register("MyProduct.Object"). So, let's create that.

JavaScript
(function() {
    Namespace = {
        register : function(ns) {
            //Split the string
            var nsParts=ns.split(".");
            //Store window in obj
            var obj=window;
            //Travese through the string parts
            for(var i=0, j=nsParts.length; i<j; i++)    {
                
                if(typeof obj[nsParts[i]] == "undefined") {
                    //Is it did not exist create it and copy it to obj
                    //so the next part can be copied into this part.
                    obj=obj[nsParts[i]]={};
                }
                else    {
                    //Still copy it to obj, cause the next one might not exist
                    obj=obj[nsParts[i]];
                }
            }
        }
    }

    NameSpace.register("MyProduct.Objects");
    MyProduct.Objects.Person=function() {
        alert("yeee this is legal")
    }   
    var P=new MyProduct.Objects.Person();
})();

This is getting somewhere. I've had this exact function in my projects for years. Until I started thinking, "since I always wrap my classes in an anonymous function, why not make that function useful?" Next to that my C# code looks like this:

C#
namespace MyProduct.Objects {
    
    public class Person {
        ....
    }
}

Of course we can't and shouldn't try make the code look the exact same way, but we could have something very similar.

JavaScript
Namespace("MyProject.Objects", function()  {
    
    MyProduct.Objects.Person=function() {
        ....    
    }
});
//notice the omission of the ()
//starting the function will be a task of the namespace function

So how would we go about that? Let's create the namespace function:

JavaScript
//This function itself is'nt Namespaced so it should be wrapped in an anonymous function
(function() {
    //no var so it will end up in the global namespace
    Namespace=function(ns, fs)   {
        //ns Namespace as . seperated string
        //fs the return function
        
        //Here's our trusty register function, only now it's inline 
        var register = function(ns) {
            //Split the string
            var nsParts=ns.split(".");
            //Store window in obj
            var obj=window;
            //Travese through the string parts
            for(var i=0, j=nsParts.length; i<j; i++)    {
                
                if(typeof obj[nsParts[i]] == "undefined") {
                    //Is it did not exist create it and copy it to obj
                    //so the next part can be copied into this part.
                    obj=obj[nsParts[i]]={};
                }
                else    {
                    //Still copy it to obj, 'cause the next one might not exist
                    obj=obj[nsParts[i]];
                }
            }
        }      
        //Let's register the namespace
        register(ns);
        
        //And call the wrapper function. 
        fs();     
    };
})();

I'm using uppercase for the first letter of the Namespace. Normally I would start a function with lowercase. But for instance the word class is a reserved word. So I fear namespace might become a reserved word in the future.

Conclusion

By many JavaScript is not considered a 'real' language. But whatever your opinion is, that's no reason to just start hacking away with long function chains and if then else's in the page code. As soon as you run in to anything that could be considered to have a state, that could change over time, you'll need to start thinking about creating objects for it. And as soon as you go there, you'll need a namespace to put them in. It might seem ridiculous at first, but the bigger you're codebase gets the more sense it will make.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Netherlands Netherlands
I'm a developer with 22+ years of experience. Starting of on a MVS mainframe, moving to building big multi-tier ERP systems with unix backends, to building web-based BI-Portals. I've seen a lot of different languages, environments and paradigmes.

At this point my main interest is webdevelopment. Mainly javascript/typescript and ASP.NET. But I also like getting my hands dirty on some PHP.

My main focus has been shifting towards full javascript the past years. Almost anything can be accomplished now. From building full offline webapps, to IoT (Tessel), to server (node).

Comments and Discussions

 
QuestionMore namespace ideas Pin
jsc428-Apr-13 6:12
professionaljsc428-Apr-13 6:12 
GeneralMy vote of 4 Pin
MB Seifollahi1-Apr-13 22:01
professionalMB Seifollahi1-Apr-13 22:01 
GeneralMy vote of 4 Pin
KarstenK1-Apr-13 20:57
mveKarstenK1-Apr-13 20:57 
Suggestionshorthand using null Pin
spring19754-Mar-13 6:51
spring19754-Mar-13 6:51 
GeneralRe: shorthand using null Pin
Sebastiaan Meijerink4-Mar-13 8:09
professionalSebastiaan Meijerink4-Mar-13 8:09 
GeneralRe: shorthand using null Pin
al13n31-May-14 1:35
al13n31-May-14 1:35 
QuestionRequire.js Pin
Yury Goltsman3-Mar-13 22:21
Yury Goltsman3-Mar-13 22:21 
AnswerRe: Require.js Pin
Sebastiaan Meijerink3-Mar-13 23:39
professionalSebastiaan Meijerink3-Mar-13 23:39 
GeneralRe: Require.js Pin
Yury Goltsman4-Mar-13 0:34
Yury Goltsman4-Mar-13 0:34 
The main purpose of the namespaces is allowing same names exist together without conflicts.
In plain Javascript all names are global (window.* for browsers) and you need namespaces for it.
In Require.js all names in module are local. The name of the module reflects their path (reminiscent to namespaces in Java). The module variable is local for scope of usage and can be named (aliased) as you want to prevent conflicts with other modules. So namespaces are useless here.

You can say that it is similar to namespaces, but it does much more than just allow looks like c++ or java

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.