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.eat
viene trovato nel prototype (=hamster
), eseguito conthis=speedy
(l’oggetto prima del punto). -
Successivamente
this.stomach.push()
deve trovare la proprietàstomach
ed invocarepush
. Cercastomach
inthis
(=speedy
), ma non trova nulla. -
Allora segue la catena del prototype e trova
stomach
inhamster
. -
Invoca
push
inhamster
, 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.