Объявление пространства имен Javascript с функцией-прототипом
Я знаю, это часто обсуждается. Но после обыска, как кто-то из 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: Неожиданный токен".
Я знаю, это косметика, но я думаю, что должен быть лучший метод объявления "пространства имен", содержащего функции класса и прототипа.
Ответы
Ответ 1
Как я это сделал, используйте "Module pattern" .
Вы в основном инкапсулируете всю свою логику "Модуль" в функцию самоисполнения, которая вернет объект, имеющий ваши классы, функции, переменные и т.д. Подумайте о возвращаемом значении как об открытии вашего 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
Ответ 2
Просто для пинков и для расширения ответа выше. Немного больше объектной нотации, ориентированной на вложенное пространство имен
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
Да, потому что вы не можете использовать этот тип цепочки в объявлении объекта
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/)
EDIT: Ого, я только заметил, что то, о чем я сказал, уже было в вопросе. Я так сожалею, что не заметил, что раньше... Ну, как вы описали себя, это правильный метод достижения этого.
В противном случае вы можете повторно написать свой код, как это, но это не совсем то, что вам нужно, и не будет работать одинаково (поскольку obj не будет самой функцией, и вам нужно будет вызвать ее главную функцию, например это obj.main();)
Namespace = {
obj: {
main : function() {
this.foo="bar";
},
prototype : {
start: function(tabinst) {
this.foo="fubar";
}
}
}
}
EDIT 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] и добавляем их в Namespace [key].prototype - успешно расширяем объект-прототип! Немного неортодоксально, но работает!