2009-01-07 13 views
18

¿Podría explicar la diferencia entre los métodos de configuración en el constructor y a través del objeto prototipo? El código siguiente muestra estas dos formas de establecer los métodos - say_hello y say_bye ambos funcionan bien:Configuración de métodos a través de objeto prototipo o en constructor, ¿diferencia?

function MessageClass() { 
    this.say_bye = function() { alert('see ya'); }; 
} 

MessageClass.prototype.say_hello = function() { alert('hello'); }; 

x = new MessageClass(); 
x.say_hello(); 
x.say_bye(); 

Respuesta

31

foxxtrot y annakata son las dos correctas, pero arrojaré mis 2 centavos.

Si usa el prototipo, cada instancia de "MessageClass" hace referencia realmente a las mismas funciones. Las funciones existen en la memoria solo una vez y se usan para todas las instancias. Si declara los métodos en el constructor (o lo agrega a una instancia específica) en lugar del prototipo, se crea una nueva función para cada instancia de MessageClass.

Habiendo dicho esto, probablemente no haya ninguna diferencia de rendimiento notable para la mayoría de los casos y tampoco es probable que vea una diferencia en el uso de la memoria. Me gustaría ir con el método prototipo a menos que tengas una razón convincente para hacer lo contrario. La única razón por la que puedo pensar que es posible que desee declarar un método en el constructor es si necesita un cierre. Por ejemplo, si tiene controladores de eventos o que quería para simular las propiedades privadas con getters/setters que podría hacer:

function MessageClass() { 
    var self = this; 
    this.clickHander = function(e) { self.someoneClickedMe = true; }; 

    var _private = 0; 
    this.getPrivate = function() { return _private; }; 
    this.setPrivate = function(val) { _private = val; }; 
} 

EDIT: Debido a que no ha habido un debate acerca de cómo esto afecta objetos extendidos por otro objeto con funciones asignado en el constructor, estoy agregando un poco más de detalle. Podría usar el término "clase" para simplificar la discusión, pero es importante tener en cuenta que js no admite clases (eso no significa que no podamos hacer un buen desarrollo OO) o no estaríamos discutiendo este tema.

La mayoría de las bibliotecas de javascript llaman al constructor en la clase base y la subclase. (por ejemplo, Object.extend de Prototype.js) Esto significa que los métodos asignados en el constructor de cada uno estarán disponibles en los objetos resultantes. Sin embargo, si extiende los objetos usted mismo, puede haber consecuencias inesperadas.

si tomo el MessageClass arriba y extenderla:

function ErrorMessageClass() {} 
ErrorMessageClass.prototype = new MessageClass(); 

errorMsg = new ErrorMessageClass(); 

Entonces errorMsg tendrá un getPrivate y el método setPrivate en él, pero no se pueden comportar como era de esperar. Debido a que esas funciones tenían un alcance cuando se asignaron (es decir, en "ErrorMessageClass.prototype = new MessageClass()" no solo se comparten los métodos get/setPrivate, también se comparte la variable _private en todas las instancias de ErrorMessageClass. Esto esencialmente hace _private a propiedad estática para ErrorMessageClass.Por ejemplo:

var errorA = new ErrorMessageClass(); 
var errorB = new ErrorMessageClass(); 
errorA.setPrivate('A'); 
console.log(errorA.getPrivate()); // prints 'A' 
console.log(errorB.getPrivate()); // prints 'A' 
errorB.setPrivate('B'); 
console.log(errorA.getPrivate()); // prints 'B' 

mismo modo con la función de clickHandler y someoneClickedMe propiedad:

errorA.clickHandler(); 
console.log(errorA.someoneClickedMe); // prints 'true' 
console.log(errorB.someoneClickedMe); // prints 'true' 

Sin embargo, cambiar esas definiciones de función para utilizar this._private:

this.getPrivate = function() { return this._private; }; 
this.setPrivate = function(val) { this._private = val; }; 

y el comportamiento de las instancias de ErrorMessageClass se vuelve más de lo que cabría esperar:

errorA.setPrivate('A'); 
errorB.setPrivate('B'); 
console.log(errorA.getPrivate()); // prints 'A' 
console.log(errorB.getPrivate()); // prints 'B' 
+0

maldito por su elocuencia :) (aunque estoy en desacuerdo, no hay una diferencia notable) – annakata

+0

Aunque si utiliza this._private, la variable es accesible desde el exterior. – Chris

+0

(técnicamente hablando, puede rastrear con un depurador de cualquier manera en la mayoría de los entornos JS, si no en todos) – Chris

5

La diferencia es cuando se derive una clase de clase de mensaje. Solo los métodos declarados en el prototipo estarán disponibles en las clases secundarias de Mensaje.

+0

Entonces, si tuviera 'BetterMessageClass.prototype = new MessageClass', ¿solo se heredaría 'say_hello'? – snitko

+0

Puedo llamar al método "say_bye" (que se declara como "this") desde la clase secundaria. Aquí está mi código: función Employee() { this.say_bye = function() {alert ('see ya'); }; } function Manager() { } Manager.prototype = new Employee; Manager.prototype.constructor = Manager; var manager = administrador nuevo(); manager.say_bye(); – Raghav

+1

@foxxtrot Eso no es correcto. Incluso los métodos declarados en 'this' dentro del constructor son accesibles en una clase secundaria. Considere el código 'errorA.setPrivate ('A')' por Prestaul, que está accediendo a un método declarado en 'this' por la clase padre' MessageClass'. – Suneel

6

Si vincula métodos por prototipo JS solo tiene que hacerlo una vez y se une a una clase de objeto (lo que hace que sea elegible para extensiones OO JS).

Si realiza la vinculación dentro de la función "clase", JS tiene que hacer el trabajo de crear y asignar para cada instancia.

+0

¿Es esto un problema de rendimiento? –

+0

sí, definitivamente – annakata

+0

¿Qué pasa si primero defino métodos como funcations, y luego digo lo siguiente en el constructor: 'this.say_bye = MessageClass_sayhello; – snitko

Cuestiones relacionadas