Javascript namespace declaration with function-pro

2019-01-30 16:21发布

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条回答
我想做一个坏孩纸
2楼-- · 2019-01-30 17:10

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
查看更多
孤傲高冷的网名
3楼-- · 2019-01-30 17:17

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楼-- · 2019-01-30 17:19

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()
查看更多
登录 后发表回答