2015-05-24 15 views
10
function A() {} 
A.prototype.x = 10; 

var a = new A(); 
alert(a.x); // 10 

A.prototype = { 
    x: 20, 
    y: 30 
}; 

alert(a.y) // undefined 
  1. Perché è delegare a old prototype of a.x e non il più recente uno?
  2. Perchéviene generato da undefined tramite il valore impostato su prototype?
+2

Perché 'a' è stato creato dal vecchio prototipo. È collegato all'oggetto prototipo, non a 'A', quindi l'assegnazione non cambia nulla. Vedi anche [here] (https://stackoverflow.com/questions/14568239/javascriptinstanceof-operator) o [there] (https: // stackoverflow.it/questions/17474390/defining-a-javascript-prototype) – Bergi

risposta

11

questo sta accadendo a causa di quando aver impostato A.prototype = obj

Invece di aggiungere proprietà al oggetto che viene ereditato da a, hai creato un oggetto del tutto nuovo come A.prototype e questo non viene ereditato da a

si consideri,

function A() {} 
A.prototype.x = 10; 

var p1 = A.prototype; // keep reference to this 

var a = new A(); 

A.prototype = {x: 20, y: 30}; 

Object.getPrototypeOf(a) === A.prototype; // false, not the new prototype 
Object.getPrototypeOf(a) === p1; // true, the old prototype 

// however 
var b = new A(); 
Object.getPrototypeOf(b) === A.prototype; // true, this is the new prototype 

Se avessi fatto le modifiche alle proprietà sul vecchio prototipo (che ho chiamato p1) questi sarebbero stati visti ereditato da a

+0

Non è che non possiamo cambiare ... __proto__ fa riferimento al vecchio prototipo attraverso il quale possiamo cambiarlo per fare riferimento a quello più recente. – Thalaivar

+0

@Thalaivar non è consigliabile usare 'obj .__ proto__' ed è molto costoso usare' Object.setPrototypeOf', se ci si aspetta che sia necessario fare questo genere di cose, o iniziare con una catena di prototipi più lunga con un quello vuoto che è possibile modificare o separare il codice per utilizzare più costruttori. –

+0

La tua risposta è nitida e chiara, ma come sai in JavaScript non esiste una situazione di deadlock, c'è sempre una soluzione, anche se a volte costosa come hai accennato. Saluti :) – Thalaivar

2

appena creato un nuovo oggetto prototipo per la classe "A", l'istanza del a

var a = new A(); 

... ha fatto copiare l'oggetto prototipo esistente riferimento per il suo esempio. Quel vecchio prototipo -oggetto è oggetto di esso stesso e non viene distrutto perché l'istanza di "A" contiene quel riferimento.

Se si desidera che la "y" da definire, è necessario creare l'oggetto nuovo utilizzando nuova, la nuova istanza avrebbe usato l'oggetto che si assinged per il prototipo - e tale istanza ha la "y" definito.

http://jsfiddle.net/ejseLum9/

+0

... eccetto i prototipi non copiati, sono referenziati. – Bergi

+1

true, ha apportato correzioni alla risposta. –

+0

Grazie! Sì, manca solo una parola :-) – Bergi

2

Perché è delegare al vecchio prototipo di a.x e non quella più recente? Perché il lancio di un.y non definito attraverso di esso è impostato in prototipo?

È stato creato un tutto new prototype object. gli oggetti creati già prima della modifica della proprietà del prototipo avranno il vecchio riferimento e il nuovo objects avrà il nuovo prototype.

// was before changing of A.prototype 
a.[[Prototype]] ----> Prototype <---- A.prototype 

// became after 
A.prototype ----> New prototype // new objects will have this prototype 
a.[[Prototype]] ----> Prototype // it will still reference to old prototype 

La regola generale è, prototype è impostato al momento della creazione dell'oggetto e in seguito non si può cambiare. È possibile aggiungere o modificare nuove proprietà esistenti di object’s prototype.

Tuttavia, è possibile eseguire una soluzione con la proprietà __proto__.

function A() {} 
A.prototype.x = 10; 

var a = new A(); 
alert(a.x); // 10 

var _newPrototype = { 
    x: 20, 
    y: 30 
}; 
A.prototype = _newPrototype; //will fail 
alert(a.y) // undefined 

A.__proto__ = _newPrototype; //will work 
alert(a.x); 
alert(a.y); 
+0

@BlueMoon: Nandri ... – Thalaivar