11

I have not yet found a common way on the Internet for creating a namespace in JavaScript.

What's the best way to create a namespace (and please list any downfalls that particular approach might have).

Timmy
  • 271
  • 1
  • 3
  • 6

8 Answers8

7
(function() {

    var usefulVariable;

    var foo = {
      bar:function(){ alert('hi') }
    };

    // leak into global namespace
    window.foo = foo;

})();

Only foo is exposed to the global namespace, and it "lives" within your private self executing anon function namespace.

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • so if I wanted to call the "bar" function, how would I do that? window.foo.bar() ? – Timmy Jul 18 '10 at 04:27
  • 1
    just invoke `foo.bar`. If I didn't expose it through `window.foo` then `foo` would only be accessible inside of that function. – meder omuraliev Jul 18 '10 at 04:30
  • 1
    Once you set window., you defeat the purpose of using namespaces. – Dan Breslau Jul 18 '10 at 04:34
  • 1
    @Dan - You don't **have** to expose it, I'm simply demonstrating certain aspects of this. – meder omuraliev Jul 18 '10 at 07:10
  • why not `this.foo=foo`, since `window` is non-standard and you're in the global scope there anyway? For that matter, why not `this.foo = {...` instead of `var foo = {...`? – Dagg Nabbit Jul 18 '10 at 07:33
  • because it's easier to read, more explicit, and more "standard" imo. – meder omuraliev Jul 18 '10 at 07:37
  • Easier to read, maybe. More explicit, not really... what else could `this` be in that situation? More standard it's not, and not to sound rude but your opinion doesn't change the 'standardness' in any way. `this` is a formalized part of ECMAScript, `window` is not. Namespaces are for reusable code e.g. libraries. What if someone wants to reuse the library in WSH or node.js? `window` will break it, `this` will not. – Dagg Nabbit Jul 18 '10 at 07:50
  • @meder -- It's up to you what you put in your answer, of course. But in a demonstration of using namespaces, I'd steer clear of using the window namespace, except to describe it as an antipattern. – Dan Breslau Jul 18 '10 at 19:55
  • _"leak into global namespace"_ - It's not a leak when you do it on purpose. – nnnnnn Aug 28 '13 at 11:46
7

In JavaScript, namespaces can only be achieved through object literals, which can be as simple as this:

var MyNS = {
    f1: function() {...},
    f2: function() {...}
};

As others have attempted to show, if you want to provide a private scope within your namespace (which is suggested), the following method is the most appropriate:

var MyNS = (function() {
    var private1 = "...", 
        private2 = "...";

    return {
        f1: function() {...},
        f2: function() {...}
    }
})();
Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
  • 2
    _"namespaces can only be achieved through object literals"_ - That's not true. An object literal is just one way to create an object, but the other object-creation methods can also be used for "namespacing" purposes. – nnnnnn Aug 28 '13 at 11:48
  • Do you have an example? – Justin Johnson Oct 24 '13 at 01:07
  • Well you can use a constructor function (called with _new_), or create an empty object with _new Object_ and then add properties one by one. (I'm not saying these techniques are _better_ than using object literals, I'm just objecting to what you said about object literals being required.) – nnnnnn Oct 24 '13 at 05:03
4

The book Pro JavaScript Design Patterns (Harmes & Diaz, 2008) provides examples of namespace creation using simple object literals or self-executing anonymous functions, both of which are illustrated in Justin Johnson's excellent answer, and these approaches work well.

Depending on the situation, it might be possible that the namespace already exists and contains members. In such a case, these approaches would destroy any members in the namespace. If this is a concern, one can use an approach similar to this to preserve any existing members, while adding new ones:

var myNamespace = (function(ns) {
    ns.f1 = function() { ... };
    ns.f2 = function() { ... };

    return ns;
})(window.myNamespace || {});

Here, myNamespace is assigned the value returned by the anonymous, self-executing function that receives the parameter ns. As one can see, the value of this parameter is either window.myNamespace or an empty object, depending on whether or not myNamespace has been previously declared.

Rick
  • 557
  • 1
  • 7
  • 16
1

To share code between scripts, you have to have at least one global variable (unless of course if you would want to do something as silly as appending your variables to an already existing object such as window.Object.

Even if you use the module pattern, you need to have a common place to share code, so, say e.g. you have three scripts:

  • core.js
  • utils.js

Then we can in the core.js script file have a module:

(function(global) {
    var coreModule = {};

    var MY_CONSTANT = 42

    var meaningOfLife = function() {
        return MY_CONSTANT;
    };
    coreModule.meaningOfLife = meaningOfLife;

    global.myRootNamespace = coreModule;
}(this));

in the utils.js:

(function(root) {
    var utilsModule = root.utils = {};

    utilsModule.bark = function() {
        console.log("WOOF!");
    };
}(myRootNamespace));

Here, we see the use of the augmentation module pattern, and namespacing the functionality depending on the nature of the functionality. This specific implementation overwrites the value of the utils property on the myRootNamespace object. However, we can write it so that it does not:

(function(root) {
    var utilsModule = root.utils = root.utils || {};

    utilsModule.bark = function() {
        console.log("WOOF!");
    };
}(myRootNamespace));

If one doesn't want to use the module pattern, we can use a simple function to define namespaces for us in a non destructive manner:

var ensureNamespace = function recur(ns, root) {
    var parts = typeof ns === 'string' ? ns.split('.') : ns;

    var r = root || this;

    if (parts[0]) {
        var next = parts.shift()
        r[next] = r[next] || {};
        return recur(parts, r[next]);
    }

    return r;
};

// maybe another file:
(function(){
    var baz = ensureNamespace("foo.bar.baz");
    // baz === window.foo.bar.baz;

    baz.qux = "Yep...";
}());

see this excellent article for more insight.

Björn Roberg
  • 2,275
  • 2
  • 15
  • 15
1

Here's my favorite way. It's a little unorthodox but it works well.

  var MyNamespace = new function(){

    this.MY_CONST_ONE = 1;
    this.MY_CONST_TWO = 2;

    this.MyClass = function (x) {
      this.x = x;
    }

    this.MyOtherClass = function (y) {
      this.y = y;
    }

  } // end of namespace

  // ... 

  var oc = new MyNamespace.MyOtherClass(123);

The interesting thing about it is the closure function is called with new instead of the normal parenthesis, so directly inside of it this refers to the object returned by the function, in other words, the 'namespace' itself.

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
1

I generally try to keep it simple and create a global object representing the namespace. If you are using multiple scripts, each declaring the namespace because they might each be used in different applications, then you would probably want to check if the object already exists.

//create the namespace - this will actually obliterate any pre-existing 
//object with the same name in the global namespace 
//(and this does happen). 
//NB ommiting the var keyword automatically chucks the object
//variable into the global namespace - which ordinarily you
//don't want to do 
MyNameSpace = {};

//and then create a class/object in the namespace
MyNameSpace.MyClass = {

            someProperty: function(){
                //do something

            },
            anotherProperty: function(){
                //doing something else
            }


};

This is pretty much what everyone else is saying. I'm just giving the really simplistic approach. Main drawback I see is that theoretically the "MyNameSpace" object could already exist - so might want to check that before you create it. Generally, if I'm going to be doing anything more complicated than that I would start thinking of a framework like JQuery or ExtJS which take a lot of pain out of these sort of things.

One more note. Part of the reason why you can't find a common way to do many things in Javascript, like creating namespaces, is that there is always more than one way to skin a cat in Javascript. Most languages are quite proscriptive on how you do things - create classes, are functional or object oriented or procedural. Javascript, on the other hand, is short of keywords and highly flexible. This maybe a good thing or a bad thing - depending on your point of view. But I quite like it.

Steve Mc
  • 3,433
  • 26
  • 35
0

I believe the module pattern has shown that it is the way to go. Object Literal Name-spacing exposes everything to the caller code outside the namespace which is essentially not a very good idea.

If you insist on creating Object Literal Namespaces, read this tutorial. I find it easy and short and I believe is very through:Object Literal Namespace (OLN) in Javascript

FidEliO
  • 875
  • 3
  • 14
  • 24
0

You can combine the answers you have received so far and accomplish much;

var Foo;  // declare in window scope.

(function(){

   var privateVar = "BAR!";

   // define in scope of closure where you can make a mess that 
   // doesn't leak into the window scope.

   Foo = {
      staticFunc: function(){ return privateVar; }
   };

})();

I generally avoid window.xxxx = yyyy; as it does not always play nicely with visual studio intellesense. There may be other issues but none that I know of.

Sky Sanders
  • 36,396
  • 8
  • 69
  • 90