レッスンに戻る

ハムスターが2匹、両方満腹なのはなぜですか?

重要度:5

「speedy」と「lazy」という2匹のハムスターがいます。これらは、一般的な「hamster」オブジェクトから継承されています。

どちらか1匹にエサをあげると、もう1匹も満腹になります。なぜですか?どのように修正できますか?

let hamster = {
  stomach: [],

  eat(food) {
    this.stomach.push(food);
  }
};

let speedy = {
  __proto__: hamster
};

let lazy = {
  __proto__: hamster
};

// This one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple

// This one also has it, why? fix please.
alert( lazy.stomach ); // apple

「speedy.eat("apple")」という呼び出しで何が起こっているのかを詳しく見てみましょう。

  1. 「speedy.eat」メソッドはプロトタイプ(=hamster)で見つかり、そのあと「this=speedy」(ドットの前にあるオブジェクト)で実行されます。

  2. 次に、「this.stomach.push()」はstomachプロパティを見つけてpushを呼び出す必要があります。それはthis(=speedy)でstomachを探しますが、何も見つかりません。

  3. 次にプロトタイプチェーンをたどってhamsterでstomachを見つけます。

  4. 次に、そのpushを呼び出して、食べ物をそのプロトタイプのstomachに加えます。

だから、すべてのハムスターは1つのstomachを共有しています!

「lazy.stomach.push(...)」と「speedy.stomach.push()」の両方について、stomachプロパティはプロトタイプ(オブジェクト自体にはありません)で見つかり、新しいデータがそこへプッシュされます。

単純な代入「this.stomach=」の場合はこのようなことは起こらないことに注意してください。

let hamster = {
  stomach: [],

  eat(food) {
    // assign to this.stomach instead of this.stomach.push
    this.stomach = [food];
  }
};

let speedy = {
   __proto__: hamster
};

let lazy = {
  __proto__: hamster
};

// Speedy one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple

// Lazy one's stomach is empty
alert( lazy.stomach ); // <nothing>

「this.stomach=」はstomachの検索を実行しないので、現在はすべてうまく動作します。値はthisオブジェクトに直接書き込まれます。

また、各ハムスターが自分のstomachを持つようにすることで、問題を完全に回避できます。

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のように特定のオブジェクトの状態を表すすべてのプロパティは、そのオブジェクト内に書き込む必要があります。これにより、このような問題が発生しません。