2012-02-13 10 views
33

Tengo tal ejemplo.¿Por qué es imposible cambiar la función del constructor del prototipo?

function Rabbit() { 
    var jumps = "yes"; 
}; 
var rabbit = new Rabbit(); 
alert(rabbit.jumps);     // undefined 
alert(Rabbit.prototype.constructor); // outputs exactly the code of the function Rabbit(); 

que quieren cambiar el código en Rabbit() para que el var jumps se convierte en público. Lo hago de esta manera:

Rabbit.prototype.constructor = function Rabbit() { 
    this.jumps = "no"; 
}; 
alert(Rabbit.prototype.constructor); // again outputs the code of function Rabbit() and with new this.jumps = "no"; 
var rabbit2 = new Rabbit();    // create new object with new constructor 
alert(rabbit2.jumps);     // but still outputs undefined 

¿Por qué no es posible cambiar el código en la función constructora de esta manera?

+0

Su segundo código dice que un conejo no salta, lo que da como resultado false, por lo tanto, el error - prueba 'this.jumps = "yes"' – wheresrhys

+0

@wheresrhys Todas las cadenas no vacías (es decir, las cadenas con longitud mayor que cero) evaluar a verdadero en JavaScript; incluso '" false "', más que, entonces, '" no "' :) – Max

Respuesta

56

Lo que está sucediendo es que Rabbit.prototype.constructor es sólo un puntero al constructor originales (function Rabit(){...}), por lo que los usuarios de la 'clase' se pueden detectar el constructor de una instancia. Por lo tanto, cuando intente hacer

Rabbit.prototype.constructor = function Rabbit() { 
    this.jumps = "no"; 
}; 

Simplemente está rompiendo el vínculo entre el constructor original y la referencia a él en el prototipo. Así que la respuesta es no, no se puede cambiar un constructor reasignando a prototype.constructor

Herencia en JS

Muchas bibliotecas implementan la herencia con algo como lo siguiente:

function extend(base, sub) { 

    function surrogateCtor() {} 
    // Copy the prototype from the base to setup inheritance 
    surrogateCtor.prototype = base.prototype; 
    // Tricky huh? 
    sub.prototype = new surrogateCtor(); 
    // The constructor property is set wrong (to the base constructor) 
    // with the above trick, let's fix it 
    sub.prototype.constructor = sub; 
} 

Se puede ver que en el código anterior, tenemos que corregir la propiedad del constructor, pero no afecta al constructor real. Ver mi post sobre JS herencia http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

Cómo redefinir un constructor Si realmente desea volver a definir un constructor, acaba de hacer

var oldProto = Rabbit.prototype; 
Rabbit = function() {...}; 
Rabbit.prototype = oldProto; 
+2

Sí, 'prototype.constructor' no afecta nada, realmente. – katspaugh

+1

+1 gran respuesta. – Jivings

0

intente lo siguiente

function Rabbit() { 
    this.jumps = "no"; 
}; 

var rabbit = new Rabbit(); 
alert(rabbit.jumps); // Prints "no" 
+2

Le doy a esta respuesta un '+ 1' si explica por qué no funciona el ajuste' saltos' en el prototipo. –

+0

Sí, gracias, sé que puedo cambiar la función original. Pero quiero saber si es posible cambiarlo de otra manera, desde un prototipo. – Green

1

Prueba esto:

Rabbit.prototype = new function(){ 
    this.jumps = "no"; 
}; 

var rabbit2 = new Rabbit();    // create new object with new constructor 
alert(rabbit2.jumps); 

En lugar de establecer el constructor desea establecer el objeto prototipo a ser una nueva función, por lo tanto, cuando se crea el objeto ejecuta el prototipo, estableciendo this.jumps en no, anulando el valor establecido por el constructor anterior.

Aquí es mi jsFiddle: http://jsfiddle.net/ZtNSV/9/

+1

Esto no funcionará, es equivalente a establecer saltos en el prototipo. Ya puedes hacer eso simplemente llamando a '' Rabbit.prototype = {jumps: 'no'}; ''. Pero realmente no querrías hacer eso, porque ese prototipo será anulado por cualquier cosa en la función constructora. – danShumway

0

Esto es maravilloso solución la creación de un objeto a partir de un literal, no desde la función constructora

En primer lugar, si quieres jumps miembro para estar contenido en el objeto, en lugar de ser simplemente una variable local en el constructor, entonces usted necesita this palabra clave.

function Rabbit() { 
    this.jumps = "yes"; 
}; 

var rabbit = new Rabbit(); 
alert(rabbit.jumps);     // not undefined anymore 

Y ahora usted puede fácilmente acceder ahora a jumps públicamente la forma en que quería:

rabbit.jumps = 'no'; 
alert(rabbit.jumps);     // outputs 'no' 

Pero aún si se crea otro objeto conejo que tendrá inicialmente 'sí' como se define en el constructor, a la derecha ?

var rabbit2 = new Rabbit(); 
alert(rabbit.jumps);      // outputs 'no' from before 
alert(rabbit2.jumps);     // outputs 'yes' 

Lo que puedes hacer es crear un conejo a partir de un objeto de conejo predeterminado. Los conejos de concreto siempre tendrán el valor predeterminado del objeto Rabbit por defecto incluso cuando lo cambies sobre la marcha a menos que hayas cambiado el valor en el objeto concreto de conejo (implementación). Esta es una solución diferente a la de @Juan Mendes, que probablemente sea la mejor, pero puede abrir otro punto de vista.

Rabbit = {jumps : 'yes'}; // default object 

rabbit = Object.create(Rabbit); 
Rabbit.jumps = 'no'; 
rabbit2 = Object.create(Rabbit); 

console.log(rabbit.jumps); // outputs "no" - from default object 
console.log(rabbit2.jumps); // outputs "no" - from default object 

// but... 
rabbit.jumps = 'yes'; 
Rabbit.jumps = 'unknown'; 

console.log(rabbit.jumps); // outputs "yes" - from concrete object 
console.log(rabbit2.jumps); // outputs "unknown" - from default object 
Cuestiones relacionadas