Javascript Namespace - Is this a good pattern?
Asked Answered
A

4

4

Objectives...

  1. Remove vars, objects etc from the global object.
  2. Remove possibility of collisions.

Firstly I implement the Yahoo namespace code (note for example purposes I am using ROOT as the root of my namespace)...

        if (typeof ROOT == "undefined" || !ROOT) {
                var ROOT = {};
        }

        ROOT.namespace = function () {
            var a = arguments,
                o = null,
                i, j, d;
            for (i = 0; i < a.length; i = i + 1) {
                d = ("" + a[i]).split(".");
                o = ROOT;
                for (j = (d[0] == "ROOT") ? 1 : 0; j < d.length; j = j + 1) {
                    o[d[j]] = o[d[j]] || {};
                    o = o[d[j]];
                }
            }
            return o;
        }

Now I declare my 1st namespace...

ROOT.namespace("UI");

            ROOT.UI = {
                utc: 12345,
                getUtc: function() {
                    return this.utc;
                }
            }

What I want to do here is to hold vars that I need for my UI (in this case the current time in UTC) so that they are not on the global object. I also want to provide some specific functionality. This should be available on every page without any sort of instanciation...

Now I want to have an object stored within my namespace structure. However, this object will need to be created multiple times. The objective here is to keep this inside my structure but allow it to be created as many times as I need. This is as follows:

 ROOT.namespace("AirportFinder");
            ROOT.AirportFinder = function(){ 
                this.var1 = 99999;

                this.Display = function() {
                    alert(this.var1);
                }            
            }

And this is the sample code to instanciate the object...

        var test1 = new ROOT.AirportFinder();
        test1.Display();

Is this a good pattern?

Artema answered 8/3, 2011 at 10:18 Comment(0)
S
1

It is indeed reasonable to have things defined on a namespace ROOT or something alike.

It's also better to use closures

(function() {
    var AirportFinder = function() { 
        this.var1 = 99999;
        this.Display = function() {
            alert(this.var1);
        }            
    };

    // do Stuff with local AirportFinder here.

    // If neccesary hoist to global namespace
    ROOT.AirportFinder = AirportFinder;
}());

If they don't need to be global. I myself use an alias ($.foobar because jQuery is global anyway) for storing any global data.

I'm afraid I can't tell you waht the .namespace function does. It's not really neccessary.

My personal preference is to always use closures to create a private namespace and hoist anything to the global/shared namespace where neccesary. This reduces the global visibility/cluster to a minimum.

Smith answered 8/3, 2011 at 10:32 Comment(4)
So the code will work fine without the Namspace function? As I understood it this is a way to "define" the namespaces?Artema
The namespace method listed just allows long chains of objects. That is, ROOT.namespace("UI.Airport.Finder") would create an object ROOT: {UI: {Airport: {Finder: {}}}}, creating new objects as needed. If you only want to create one level of children, it's not needed.Anticlinorium
In terms of closures, does the above code: run as soon as the script is loaded into the browser, create an anonymous function that declares my Airport function and execute it straight away? Also adding the AirportFinder functon to my ROOT namespace? How does this reduce the clutter on global?Artema
@RemotecUK yes the closure is created and run immediatly. Your supposed to have multiple private things in your closure and if you need to access them globally / across scripts / on the page directly you can optionally host it to your global ROOT namespace. If it's needed globally you have to hoist it somewhere. If it's not needed globally you keep it private.Smith
O
0

Slightly pointing you a little to the side, off the path of your question: Have a look at YUI3 (http://developer.yahoo.com/yui/3/) - you don't have (to have) anything in the global namespace there, you get a private sandbox. Great concept, I love that library and its conocepts (YUI3, not talking about old YUI2). The way it does that is of course simple and you could do that too: The dynamic module loader of YUI3 loads your module (.js file(s)), creates a sandbox (just a closure) and calls your callback, giving it a handle for the sandbox. No other code anywhere can gain access to that sandbox and your own names. Within that sandbox you can (and should) go on using the various encapsulation patterns. This YUI3 concept is great for mashups with foreign code, especially when mashups become more dynamic in nature (e.g. user triggered), instead of just integrating Google Maps or other well-known APIs by the programmers themselves.

Otology answered 8/3, 2011 at 11:13 Comment(0)
H
0

I tried to do a similar thing:

var namespace = function(str, root) {
    var chunks = str.split('.');
    if(!root)
        root = window;
    var current = root;
    for(var i = 0; i < chunks.length; i++) {
        if (!current.hasOwnProperty(chunks[i]))
            current[chunks[i]] = {};
        current = current[chunks[i]];
    }
    return current;
};

// ----- USAGE ------

namespace('ivar.util.array');

ivar.util.array.foo = 'bar';
alert(ivar.util.array.foo);

namespace('string', ivar.util);

ivar.util.string.foo = 'baz';
alert(ivar.util.string.foo); 

Try it out: http://jsfiddle.net/stamat/Kb5xY/

Blog post: http://stamat.wordpress.com/2013/04/12/javascript-elegant-namespace-declaration/

Harshman answered 12/4, 2013 at 13:15 Comment(0)
S
0

By using an anonymous self-executing function, you can allow for public and private attributes/methods.

This is the pattern I like the most:

(function ($, MyObject, undefined) {
  MyObject.publicFunction = function() {
      console.log("This is a public function!");
  };
  var privateFunction = function() {
    console.log("This is a private function!");
  };

  MyObject.sayStuff = function() {
    this.publicFunction();
    privateFunction();
    privateNumber++;
    console.log(privateNumber);
  };
  var privateNumber = 0;

  // You can even nest the namespaces
  MyObject.nestedNamespace = MyObject.nestedNamespace || {};      
  MyObject.nestedNamespace.logNestedMessage = function () {    
     console.log("Nested!!");
  };

}(jQuery, window.MyObject = window.MyObject || {}));

MyObject.sayStuff();
MyObject.nestedNamespace.logNestedMessage();
MyObject.publicFunction();

Learned about it from the comments in this article.

Selfpossession answered 11/7, 2013 at 23:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.