2011-08-21 21 views
17

Lo sé, esto se discute a menudo. Pero después de buscar como alguien del siglo XIX, necesito algunos consejos. No tengo ningún problema al declarar un "espacio de nombres", pero cuando se trata de una función prototype.foo, me quedé atrapado. He encontrado una manera, pero no me gusta:declaración del espacio de nombres de Javascript con función-prototipo

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

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

Ahora, ya que soy un poco neurótica en el caso de secuencias de comandos, me gustaría tener algo como esto:

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

Pero luego arroja un error: "Uncaught SyntaxError: Token inesperado".

Lo sé, esto es estético, pero creo que tiene que haber un mejor método para declarar un "espacio de nombres" que contenga una clase y funciones de prototipo.

Respuesta

29

La forma en que lo haría es usar el "Module pattern".
Básicamente, encapsula toda su lógica de "Módulo" en una función autoejecutable que devolvería un objeto que tenga sus clases, funciones, variables, etc. ... Piense en el valor de retorno como exponiendo su API de Módulo.

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() 

Con el fin de encapsular aún más los métodos de la clase "obj" y constructor podríamos hacer lo siguiente:

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

Hay también una característica importante que viene gratis con este patrón, que es " Variables privadas ", considere lo siguiente:

/** 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 
+0

Buen enfoque, +1. – Jiri

+0

Thans Amjad, esto es genial. Pero ahora estoy tropezando de nuevo. ¿Lo veo bien? Con este enfoque, no es posible crear una función Namespace.blah() que esté separada de obj? –

+2

@Johnny Si entiendo bien su pregunta, simplemente agregue una función 'blah' al objeto de devolución: '. . retorno { obj: obj, obj2: obj2, bla: function() {/ * hacer algo * /}} ; ' –

2

Sí, porque, no se puede utilizar este tipo de encadenamiento en una declaración de objeto

obj.prototype o obj.something aquí, porque el lenguaje obj ve como un valor que no es objeto. Usted puede fingir un efecto tal como esto

Namespace = {}; 

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

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

console.log(Namespace.obj.prototype); 

(ver este violín http://jsfiddle.net/WewnF/)

EDIT: Wow, me he dado cuenta de que lo que he dicho ya dentro de la pregunta era. Lo siento mucho no haberlo notado antes ... Bueno, la forma en que te describes a ti mismo es el método correcto para lograr esto.

De lo contrario, puede volver a escribir su código de esta manera, pero no es exactamente lo que busca y no funcionará igual (ya que obj no será una función en sí y tendrá que llamar a su función principal como esto obj.main();)

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

EDIT 2: Ver este violín 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"); 

esto tendrá exactamente el mismo efecto. Explicación: estamos declarando nuestros objetos como propiedades-funciones normales, y luego usamos un objeto prototipo maestro que contiene objetos con los mismos nombres que antes, por ejemplo para cada Namespace.obj, también hay un Namespace.prototype.obj que contiene las funciones que queremos agregar en la cadena de prototipos.

luego con namespace.protoInit(), iteramos a través de todas las propiedades - y extraemos las funciones de Namespace.prototype [key] y las agregamos al Namespace [key] .prototype - extendiendo con éxito el objeto prototipo! Un poco heterodoxo, pero funciona!

+0

El primer fragmento en su edición no funcionará como podría pensar. 'obj.main' y' obj.prototype' son dos funciones independientes diferentes. Sí, 'this' se referirá al mismo objeto si los llama sin' new', pero solo porque se refiere a 'window'. Entonces harás 'foo' global. –

+0

Su segundo ejemplo limita 'Namespace' para que solo contenga una" clase "que de alguna manera derrota el propósito del espacio de nombres. –

+0

Tiene razón en el primer ejemplo, y me siento estúpido por no haberlo notado antes, pero no estoy de acuerdo con el segundo. ¿Por qué lo limita a una sola "clase"? Si usa más objetos, iterará a través de ellos y les asignará los valores de prototipo correctos. – Pantelis

3

Just for kicks and expandir la respuesta anterior. Un poco más de notación de objetos orientada en función del espacio de nombres anidados

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() 
Cuestiones relacionadas