2011-07-25 18 views
5

Estoy tratando de descubrir el patrón básico para crear una biblioteca de JavaScript (clase). Quiero hacerlo de tal manera que no contamine el espacio de nombres global con un montón de basura, pero permitiendo que la clase tenga variables de instancia y métodos públicos que modifiquen esas variables de instancia.JavaScript library pattern

Considere el siguiente ejemplo de juguete. Quiero hacer una clase Foo. Debe contener un miembro de instancia, bar, que es un número. Debe haber un constructor para Foo que toma un número e inicializa su instancia bar con ese número. Debería haber un método de instancia al que pueda llamar en un objeto Foo para modificar bar. Tal vez el código que utiliza la biblioteca se ve así:

var foo1 = new Foo(1); 
var foo2 = new Foo(2); 
console.log(foo1.bar); // should print "1" 
console.log(foo2.bar); // should print "2" 
foo2.changeBar(42); 
console.log(foo1.bar); // should print "1" 
console.log(foo2.bar); // should print "42" 

La resultante foo.js sería utilizado por una aplicación web y, por tanto, incluye a través de una etiqueta de script en el código HTML.

He hecho un poco de búsqueda con Google, pero todavía tengo que encontrar un esquema único, conciso y genérico de cómo diseñar una clase de JavaScript (utilizada como biblioteca).

Respuesta

9
(function() { 
    Foo = function (num) { 
     this.changeBar(num); 
    }; 

    var privateMethod = function (x) { 
     if (this.bar === 999) { 
      this.bar = x; 
     } 
    }; 

    Foo.prototype.changeBar = function (num) { 
     this.bar = num; 
     privateMethod.call(this, 1); 
    }; 

}()); 

Esa es la forma más sencilla de hacerlo. No es necesario que incluya la definición en un cierre, más una cuestión de estilo.

+0

+1 también. El cierre tiene algunas ventajas sutiles. Puede definir funciones "privadas" dentro del cierre a las que pueden llamar sus funciones de prototipo y miembros. – selbie

+0

@selbie ¿cómo se definiría una función privada así, y cómo se llamaría? –

+1

He editado la respuesta de Evan anterior para incluir un método privado. La función "privateMethod" no puede invocarse excepto por otras funciones dentro del cierre. – selbie

3

El modelo Module Pattern es probablemente el más utilizado hoy en día.

var Foo = (function() { 
    var _thisIsAPrivateVar; 

    function thisIsAPrivateMethod() { 
    } 

    return { 
     thisIsAPublicMethod : function() { 
      // can still access the "private" variable and method 
     } 
    }; 

})(); 
7

Aprovechando la respuesta de Evan, para mostrar algunas otras posibilidades. La mayoría de los casos normales solo usan algunos de estos.

(function() { 
    //When we create variables inside a function they can only be seen by other 
    // inner functions. Wraping all our code here makes sure noone gets to see 
    // the private stuff. 

    //The first opening parenthesis is required for Javascript to parse it 
    //correctly though 


    //this is the constructor function 
    //Note how we set a global variable (Foo) to make it available outside. 
    Foo = function(num, another_num) { 

     this.changeBar(num); 

     //sometimes you will want to make a method that modifies a variable 
     //that can't be acessed via this.xxx. You can use a closure here for that 
     //(there are some performance considerations though) 

     this.baz = function(){ 
      console.log(another_num); 
     } 

     //Setting methods "by hand" like this is also useful if you want to 
     //do multiple inheritance, since you can just set all methods of the 
     //second class by hand here if you want. 
    } 

    //Things on Foo.prototype will be available for all Foo objects, 
    // via prototypal inheritance magic. 
    Foo.prototype.changeBar = function(num) { 
     this.bar = num; 
    } 

    var a_secret_variable = 42; 

    function my_private_function(){ 
     console.log(a_secret_variable); 
    } 

    //All private variables can be normaly used (by functions that can see them). 
    Foo.prototype.use_magic = function(){ 
     my_private_function(); 
    } 

}()); 
//The "fake" function is imediatelly called, 
//so in the end all it does is create a inner scope.