Perché è imansible modificare la funzione di costruzione dal prototipo?

Ho un esempio

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

Voglio cambiare il codice in Rabbit() modo che i var jumps diventino pubblici. Lo faccio in questo modo:

 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 

Perché non è ansible modificare il codice nella funzione di costruzione in questo modo?

Non è ansible modificare un costruttore riassegnando a prototype.constructor

Quello che sta accadendo è che Rabbit.prototype.constructor è un puntatore al costruttore originale ( function Rabit(){...} ), in modo che gli utenti della ‘class’ possano rilevare il costruttore da un’istanza. Pertanto, quando provi a fare:

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

Stai solo andando a influenzare il codice che si basa su prototype.constructor per creare istanze dinamiche di oggetti da istanze.

Quando si chiama new X , il motore JS non fa riferimento a X.prototype.constructor , utilizza la X come funzione di costruzione e X.prototype come prototipo dell’object appena creato., Ignorando X.prototype.constructor .

Un buon modo per spiegarlo è implementare noi stessi il new operatore. (Crockford sarà felice, non più nuovo;)

 // `new` emulator // // Doesn't reference `.constructor` to show that prototype.constructor is not used // when istantiating objects a la `new` function make(ctorFun, argsArray) { // New instance attached to the prototype but the constructor // hasn't been called on it. const newInstance = Object.create(ctorFun.prototype); ctorFun.apply(newInstance, argsArray); return newInstance; } // If you create a utility function to create from instance, then it uses the // inherited `constructor` property and your change would affect that. function makeFromInstance(instance, argsArray) { return make(instance.constructor, argsArray); } function X(jumps) { this.jumps = jumps; } // Flip the constructor, see what it affects X.prototype.constructor = function(jumps) { this.jumps = !jumps; } const xFromConstructorIsGood = make(X, [true]); const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]); console.log({ xFromConstructorIsGood, xFromInstanceIsBad }); 

Prova questo:

 Rabbit.prototype = new function(){ this.jumps = "no"; }; var rabbit2 = new Rabbit(); // create new object with new constructor alert(rabbit2.jumps); 

Invece di impostare il costruttore, si vuole impostare il prototipo Object come nuova funzione, quindi quando l’Object viene creato esegue il prototipo, impostando this.jumps su no, sovrascrivendo il valore impostato dal costruttore precedente.

Ecco il mio jsfiddle: http://jsfiddle.net/ZtNSV/9/

Prova quanto segue

 function Rabbit() { this.jumps = "no"; }; var rabbit = new Rabbit(); alert(rabbit.jumps); // Prints "no" 

Questa è una soluzione meravigliosa che crea un object da una funzione letterale, non dalla funzione di costruzione.

In primo luogo, se vuoi che il membro di jumps sia contenuto nell’object, piuttosto che essere solo una variabile locale nel costruttore allora hai bisogno di this parola chiave.

 function Rabbit() { this.jumps = "yes"; }; var rabbit = new Rabbit(); alert(rabbit.jumps); // not undefined anymore 

E ora puoi facilmente accedere ora ai jumps pubblicamente come volevi:

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

Tuttavia, se crei un altro object Rabbit, inizialmente avrà “sì” come definito nel costruttore, giusto?

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

Quello che potresti fare è creare un rabbitmq da qualche object Rabbit predefinito. I conigli concreti avranno sempre il valore predefinito dall’object Rabbit predefinito anche quando lo si cambia al volo, a meno che non si sia modificato il valore in concreto object rabbitmq (implementazione). Questa è una soluzione diversa dalla soluzione di @Juan Mendes che è probabilmente la migliore ma può aprire un altro punto di 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