Объявление пространства имен Javascript с функцией-прототипом - PullRequest
18 голосов
/ 21 августа 2011

Я знаю, это часто обсуждается. Но после поисков вокруг, как кто-то из 19-го века, мне нужен совет. У меня нет проблем с объявлением «пространства имен», но когда дело доходит до функции prototype.foo, я застрял. Я нашел способ, но мне не нравится:

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

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

Теперь, поскольку я немного невротичен в случае написания сценариев, я хотел бы иметь что-то вроде этого:

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

Но тогда выдает ошибку: «Uncaught SyntaxError: Неожиданный токен.»

Я знаю, это косметика, но я думаю, что должен быть лучший способ объявления "пространства имен", содержащего класс и функции-прототипы.

Ответы [ 3 ]

33 голосов
/ 21 августа 2011

Я бы сделал это, используя «Шаблон модуля» .
По сути, вы инкапсулируете всю свою логику «модуля» в самозапускающуюся функцию, которая будет возвращать объект с вашими классами, функциями, переменными и т. Д. Думайте о возвращаемом значении как о представлении вашего 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()

Чтобы дополнительно инкапсулировать методы и конструктор класса obj, мы можем сделать следующее:

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

Существует также важная функция, которая предоставляется бесплатно при использовании этого шаблона, а именно «Частные переменные», рассмотрим следующее:

/** 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 голосов
/ 04 сентября 2015

Просто для пинки и для расширения на ответ выше.Чуть больше объектной нотации, ориентированной на вложенное пространство имен

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()
3 голосов
/ 21 августа 2011

Да, потому что вы не можете использовать этот тип цепочки в объявлении объекта

obj.prototype или obj.something здесь, потому что язык видит obj как необъектное значение. Вы можете подделать такой эффект, как этот

Namespace = {};

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

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

console.log( Namespace.obj.prototype );

(см. Эту скрипку http://jsfiddle.net/WewnF/)

РЕДАКТИРОВАТЬ: Wow я только что заметил, что то, что я сказал, уже было в вопросе. Мне очень жаль, что я не заметил, что раньше ... Ну, то, как вы описали себя, является правильным способом достижения этого.

В противном случае вы можете переписать свой код следующим образом - но это не совсем то, что вам нужно, и он не будет работать так же (поскольку obj не будет самой функцией, и вам придется вызывать ее основную функцию следующим образом this obj.main ();)

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

РЕДАКТИРОВАТЬ 2: Смотрите эту скрипку 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" );

Это будет иметь точно такой же эффект. Объяснение: мы объявляем наши объекты как обычные свойства-функции, а затем используем главный объект-прототип, который содержит объекты с такими же именами, как указано выше, например, для каждого Namespace.obj, есть также Namespace.prototype.obj, который содержит функции, которые мы хотим добавить в цепочку прототипов.

затем с помощью namespace.protoInit () мы перебираем все свойства - и извлекаем функции из Namespace.prototype [key] и добавляем их в пространство имен [key] .prototype - успешно расширяя объект-прототип! Немного неортодоксально, но работает!

...