レッスンに戻る

「this」を失う関数を修正する

importance: 5

以下のコードでaskPassword()を呼び出すと、パスワードを確認し、答えに応じてuser.loginOk/loginFailを呼び出す必要があります。

しかし、エラーが発生します。なぜでしょうか?

ハイライトされた行を修正して、すべてが正常に動作するようにしてください(他の行は変更しないでください)。

function askPassword(ok, fail) {
  let password = prompt("Password?", '');
  if (password == "rockstar") ok();
  else fail();
}

let user = {
  name: 'John',

  loginOk() {
    alert(`${this.name} logged in`);
  },

  loginFail() {
    alert(`${this.name} failed to log in`);
  },

};

askPassword(user.loginOk, user.loginFail);

askがオブジェクトなしで関数loginOk/loginFailを取得するため、エラーが発生します。

これらの関数は呼び出されると当然this=undefinedとみなされます。

コンテキストをbindしてみましょう

function askPassword(ok, fail) {
  let password = prompt("Password?", '');
  if (password == "rockstar") ok();
  else fail();
}

let user = {
  name: 'John',

  loginOk() {
    alert(`${this.name} logged in`);
  },

  loginFail() {
    alert(`${this.name} failed to log in`);
  },

};

askPassword(user.loginOk.bind(user), user.loginFail.bind(user));

これで動作するようになりました。

代替の解決策としては、次の方法があります。

//...
askPassword(() => user.loginOk(), () => user.loginFail());

通常、これは機能し、見かけもよくなります。

ただし、askPasswordが呼び出された、訪問者が答えて() => user.loginOk()を呼び出すuser変数が変更される可能性があるなど、より複雑な状況では信頼性が少し低くなります。