2011-11-22 15 views
9

ottengo un risultato inatteso con il seguente codice:Javascript proprietà prototype non funziona come previsto con i campi di array e oggetti

var TestModel, u, u2; 

function TestModel() {} 
TestModel.prototype.a = null; 
TestModel.prototype.b = []; 

u = new TestModel(); 
u.a = 1; 
u.b.push(1); 

u2 = new TestModel(); 
u2.a = 2; 
u2.b.push(2); 

console.log(u.a, u.b);  // outputs: 1 [1,2] 
console.log(u2.a, u2.b); // outputs: 2 [1,2] 

Trovo sorprendente che u.b e u2.b contengono gli stessi valori, anche se ogni istanza di TestModel dovrebbe avere le sue variabili di istanza in base a come ho configurato il prototipo. Quindi questo è l'output che mi aspettavo:

console.log(u.a, u.b);  // expecting: 1 [1] 
console.log(u2.a, u2.b); // expecting: 2 [2] 

la stessa cosa accade se ho impostato b ad essere un oggetto e impostare i tasti su di esso invece di usarlo come un array. Cosa non sto comprendendo qui?

risposta

1

L'array è in entrambi i casi lo stesso array, ovvero quello impostato sul prototipo. Ciò significa che entrambe le chiamate .push agiscono su tale matrice, in modo che tutti questi sono [1, 2]:

TestModel.prototype.b 
u.b 
u2.b 

si riferiscono tutti alla stessa proprietà.

Il prototipo viene in genere utilizzato per le funzioni, in modo che tutte le istanze condividano le stesse funzioni. Se si sta andando a modificare le proprietà del prototipo, quindi si rifletteranno anche per tutte le istanze, che in questo caso è probabilmente indesiderabile. Se le istanze devono avere ciascuna una matrice personalizzata, dichiarare anche una personalizzata per ogni istanza anziché tramite prototipo.

13

C'è una differenza tra che assegna valori e che fa riferimento a.

u.a = 1; 

creerà una nuova a proprietà sull'oggetto cui fa riferimento u. Prima della cessione, u.a sarà fare riferimento a TestModel.prototype.a, ma l'assegnazione di un nuovo valore in realtà crea una nuova proprietà per l'oggetto reale:

enter image description here

Dopo l'assegnazione:

enter image description here

D'altra hand,

u.b.push(1); 

non crea una nuova proprietà. Farà riferimento alla proprietà esistente, la matrice, che è TestModel.prototype.b.

anche se ogni istanza di TestModel dovrebbe avere le sue variabili propria istanza in base a come ho installato il prototipo

Tutte le istanze fanno riferimento allo stesso prototipo, di conseguenza, essi fanno riferimento alle stesse proprietà del prototipo ha. Si può facilmente vedere che poiché TestMode.prototype === u.b, TestMode.prototype === u2.b e u.b === u2.b producono tutti true.

Funzionerebbe se si assegna un nuovo valore anche per u.b e u2.b così:

u.b = []; 

che viene normalmente fatto nel costruttore:

function TestModel() { 
    this.b = []; 
} 
+0

Grazie mille! Non ero a conoscenza di quella sottile differenza. Quindi in pratica dovrei inizializzare tutte le variabili 'istanza' nel mio costruttore prima di manipolarle altrove. – hiddentao

+0

@hiddentao: esattamente. È consentito assegnare i tipi primitivi alle proprietà di prototipo, come valori predefiniti, ma gli oggetti e gli array devono essere inizializzati nel costruttore se sono "per istanza". Normalmente definisco ancora la proprietà sul prototipo, ma la inizializzo con 'null' (come hai fatto con' TestModel.prototype.a'). –

+0

@Felix, quale strumento stavi usando per ottenere quel bel grafico dei valori in TestModel? –

3

proprietà prototipi sono esattamente il contrario di ogni istanza che ha le proprie variabili, il punto di prototipo è che tutte le istanze condividono automaticamente le stesse proprietà del prototipo, quindi non sono necessarie funzioni di ridefinizione per ogni istanza.

Volete ogni istanza di avere la propria serie in questo modo:

function TestModel() { 
this.a = null; 
this.b = []; 
} 
Problemi correlati