なぜ2匹のハムスターがお腹一杯?
私たちは2匹のハムスターを持っています: speedy
と lazy
は一般的な hamster
オブジェクトを継承しています。
そのうちの1匹に餌をやるとき、もう1匹もお腹一杯になります。なぜでしょう?どのように修正しますか?
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// 一方が食べ物を見つけました
speedy.eat("apple");
alert( speedy.stomach ); // apple
// もう一方も持っています。なぜでしょう?修正してください。
alert( lazy.stomach ); // apple
呼び出し speedy.eat("apple")
の中で何が起きているか注意深く見ていきましょう。
-
メソッド
speedy.eat
はプロトタイプ(=hamster
) で見つかり、this=speedy
(ドットの前のオブジェクト)で実行されます。 -
次に、
this.stomach.push()
はstomach
プロパティを見つけ、push
する必要があります。それはthis
(=speedy
) の中でstomach
を探しますが、見つかりません。 -
次に、プロトタイプチェーンに従って、
hamster
の中でstomach
を見つけます。 -
そして、
push
を呼び出し、プロトタイプの stomach の中に食べ物を追加します。
従って、すべてのハムスターは1つの胃(stomach)を共有しています!
毎回、stomach
はプロトタイプから取られ、stomach.push
は “その場” で変更します。
シンプルな代入 this.stomach=
の場合には、このようなことは起こらないことに注意してください。:
let hamster = {
stomach: [],
eat(food) {
// this.stomach.push の代わりに this.stomach に代入する
this.stomach = [food];
}
};
let speedy = {
__proto__: hamster
};
let lazy = {
__proto__: hamster
};
// Speedy は食べ物を見つけました
speedy.eat("apple");
alert( speedy.stomach ); // apple
// Lazy の胃は空っぽです
alert( lazy.stomach ); // <nothing>
今、すべてうまく行きました。なぜなら this.stomach=
は stomach
を参照しないからです。値は直接 this
オブジェクトに書き込まれます。
また、各ハムスターが自身の胃をもつことで問題を避けることができます:
let hamster = {
stomach: [],
eat(food) {
this.stomach.push(food);
}
};
let speedy = {
__proto__: hamster,
stomach: []
};
let lazy = {
__proto__: hamster,
stomach: []
};
// Speedy one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple
// Lazy one's stomach is empty
alert( lazy.stomach ); // <nothing>
一般的な解決策として、上の stomach
のような、特定のオブジェクトの状態を説明するすべてのプロパティは通常そのオブジェクトの中に書かれます。それはこのような問題を防ぎます。