18

I know, this is often discussed. But after searching around like someone out of the 19th century, I need some advice. I have no problem by declaring a "namespace", but when it comes to a prototype.foo function, I stuck. I found a way, but I don't like it:

Namespace = {}
Namespace.obj = function() {
    this.foo="bar";
}
Namespace.obj.prototype.start = function() {
    this.foo="fubar";
}

blah = new Namespace.obj();
blah.start();

Now, since I'm a little neurotic in case of scripting, I would like to have something like this:

Namespace = {
    obj: function() {
        this.foo="bar";
    },
    obj.prototype.start: function(tabinst) {
        this.foo="fubar";
    }
}
...

But then it throws an error: "Uncaught SyntaxError: Unexpected token ."

I know, this is cosmetic, but I think that there has to be a better method of declaring a "namespace" containing a class and prototype functions.

3 Answers 3

34

The way I would do it is using the "Module pattern".
You basically encapsulate all your "Module" logic in a self executing function that would return an object having your classes, functions, variables etc... Think of the return value as exposing your Module API.

Namespace = (function () {
    /** Class obj **/
    var obj = function () {
        this.foo = 'bar';
    };
    obj.prototype = {
        start: function () {
            this.foo = 'fubar';
        }
    };

    /** Class obj2 **/  
    var obj2 = function () {
        this.bar = 'foo'
    };
    obj2.prototype = {
        start: function () {
            this.bar = 'barfoo';
        },
        end: function () {
            this.bar = '';
        }
    };
    return {
        obj : obj,
        obj2: obj2
    };
})();

var o = new Namespace.obj()
o.start()

In order to further encapsulate the "obj" class methods and constructor we could do the following:

/** Class obj **/
var obj = (function () {
    /** class Constructor **/
    var obj = function () {
        this.foo = 'bar';
    };
    /** class methods **/
    obj.prototype = {
        start: function () {
            this.foo = 'fubar';
        }
    };
    return obj;
})();

There is also an important feature that comes for free using this pattern, which is "Private variables", consider the following:

/** Class Foo **/
var Foo = (function () {
    // Private variables
    var private_number = 200
    /** class Constructor **/
    var Foo = function () {
        this.bar = 0;
    };
    /** class methods **/
    Foo.prototype = {
        add: function () {
            this.bar += private_number;
        }
    };
    return Foo;
})();

foo = new Foo();
alert(foo.bar); // 0
foo.add(); 
alert(foo.bar);// 200
alert(foo.private_number) //undefined
Sign up to request clarification or add additional context in comments.

3 Comments

Thans Amjad, this is great. But now I'm stumbling again. Do I see it right: With this approach it's not possible to make a Namespace.blah() function that is detached form obj?
@Johnny If I understand your question right, just add a blah function to the return object: . . return { obj : obj, obj2: obj2, blah: function () {/* do something */} };
Amjad, thanks a lot. This is exactly what I wanted! Now I got it.
3

Yes because, you cannot use this type of chaining in an object declaration

obj.prototype or obj.something here, because the language sees obj as a non-object value. You can fake such an effect like this

Namespace = {};

Namespace.obj =function() {
        this.foo="bar";
};

Namespace.obj.prototype.start = function(tabinst) {
        this.foo="fubar";
};

console.log( Namespace.obj.prototype );

(see this fiddle http://jsfiddle.net/WewnF/ )

EDIT: Wow, I just noticed that what I said was already within the question. I 'm so sorry did not notice that sooner... Well the way you described yourself is the correct method of achieving this.

Otherwise you can re-write your code like this - but is not exactly what you 're after and won't work the same (since obj won't be a function itself and you will have to call its main function like this obj.main(); )

Namespace = {
    obj: {
          main : function() {
               this.foo="bar";
          },
          prototype : {
             start: function(tabinst) {
             this.foo="fubar";
             }
          }
    }
}

EDIT 2: See this fiddle http://jsfiddle.net/NmA3v/1/

Namespace = {
    obj: function() {
        this.foo="bar";
    },
    prototype: {
        obj : {
            start : function( hi ) {
                 alert( hi ); 
            }  
        }

    },

    initProto : function(){
        for( var key in Namespace )
        {
            if( key !== "prototype" )
            {
                for( var jey in Namespace.prototype[ key ] )
                    Namespace[ key ].prototype[ jey ] =  Namespace.prototype[ key ][ jey ];  
            }
        }
    }
}

Namespace.initProto();

console.log( Namespace.obj);

var test  = new Namespace.obj();

test.start( "Hello World" );

This will have the exact same effect. Explanation : we are declaring our objects as normal properties-functions, and then use a master prototype object which containers objects with the same names as above, for example for each Namespace.obj, there is also a Namespace.prototype.obj which contains the functions we want to add in the prototype chain.

then with namespace.protoInit(), we iterate through all properties - and extract the functions from the Namespace.prototype[ key ] and add them to Namespace[ key ].prototype - succesfully extending the prototype object! A bit unorthodox, but works!

4 Comments

The first snippet in your edit will not work as you might think. obj.main and obj.prototype are two different independent functions. Yes, this will refer to the same object if you call them without new, but only because it refers to window. So you will make foo global.
Your second example limits Namespace to only contain one "class" which somehow defeats the purpose of the namespace.
You are correct for the first example, and I feel stupid for not noticing this sooner, but I disagree about the second one. Why does it limit it to only one "class" ? If you use more objects, it will iterate through them and assign to them the correct prototype values.
Ah true, you have obj inside prototype.... I missed that. Sorry for that. I would still say this is not a straightforward approach.
3

Just for kicks and to expand on the answer above. A bit more object notation oriented based on nested namespace

var NS = {};

// Class List
NS.Classes = {
  Shape: (function(){
    // Private
    var whateveryouwishboss = false;

    // Public
    var Shape = function(x,y,w,h){
      this.x = x;
      this.y = y;
      this.w = w;
      this.h = h;
    };
    Shape.prototype = {
      draw: function(){
        //... Im on prototype Shape 
      }
    }
    return Shape;
  })(),
  Person: (function(){
    //....
  })()
}

/////// Let the games begin

var rect = new NS.Class.Shape(0,0,10,10);
rect.draw()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.