Perché entrambi i criceti sono sazi?
Abbiamo due criceti: speedy e lazy, che ereditano dall’oggetto hamster.
Quando nutriamo uno di loro, anche l’altro è sazio. Perché? Come possiamo sistemare il problema?
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// Questo ha trovato il cibo
speedy.eat("apple");
alert( speedy.stomach ); // apple
// Anche questo lo ha ricevuto, perché? provate a sistemarlo
alert( lazy.stomach ); // apple
Guardiamo attentamente cosa succede nella chiamata speedy.eat("apple").
-
Il metodo
speedy.eatviene trovato nel prototype (=hamster), eseguito conthis=speedy(l’oggetto prima del punto). -
Successivamente
this.stomach.push()deve trovare la proprietàstomached invocarepush. Cercastomachinthis(=speedy), ma non trova nulla. -
Allora segue la catena del prototype e trova
stomachinhamster. -
Invoca
pushinhamster, aggiungendo il cibo nello stomaco del prototype.
Quindi tutti i criceti condividono un unico stomaco!
Per entrambi lazy.stomach.push(...) e speedy.stomach.push(), la proprietà stomach viene trovata nel prototype (poiché non si trova negli oggetti), quindi i cambiamenti avvengono li.
Da notare che questo non accade nel caso di una semplice assegnazione this.stomach=:
let hamster = {
stomach: [],
eat(food) {
// assegnamo a this.stomach invece di this.stomach.push
this.stomach = [food];
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// Speedy trova il cibo
speedy.eat("apple");
alert( speedy.stomach ); // apple
// lo stomaco di Lazy è vuoto
alert( lazy.stomach ); // <nothing>
Ora tutto funziona bene, perché this.stomach= non deve andare alla ricerca di stomach. Il valore è scritto direttamente nell’oggetto this.
Possiamo anche evitare completamente il problema, facendo in modo che ogni criceto abbia il suo stomaco:
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster,
stomach: []
};
let lazy = {
__proto__: hamster,
stomach: []
};
// Speedy trova il cibo
speedy.eat("apple");
alert( speedy.stomach ); // apple
// lo stomaco di Lazy è vuoto
alert( lazy.stomach ); // <nothing>
Come soluzione comune, tutte le proprietà che descrivono un particolare stato dell’oggetto, come stomach, dovrebbero essere memorizzate nell’oggetto. In questo modo eviteremo il problema.