Вернуться к уроку

Использование функции вопросов с каррингом

важность: 5

Эта задача – усложнённый вариант задачи Использование функции вопросов. В ней объект user изменён.

Теперь заменим две функции user.loginOk() и user.loginFail() на единый метод: user.loginDone(true/false), который нужно вызвать с true при верном ответе и с false – при неверном.

Код ниже делает это, соответствующий фрагмент выделен.

Сейчас он обладает важным недостатком: при записи в user другого значения объект перестанет корректно работать, вы увидите это, запустив пример ниже (будет ошибка).

Как бы вы написали правильно?

Исправьте выделенный фрагмент, чтобы код заработал.

"use strict";

function ask(question, answer, ok, fail) {
  var result = prompt(question, '');
  if (result.toLowerCase() == answer.toLowerCase()) ok();
  else fail();
}

var user = {
  login: 'Василий',
  password: '12345',

  // метод для вызова из ask
  loginDone: function(result) {
    alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
  },

  checkPassword: function() {
    ask("Ваш пароль?", this.password,
      function() {
        user.loginDone(true);
      },
      function() {
        user.loginDone(false);
      }
    );
  }
};

var vasya = user;
user = null;
vasya.checkPassword();

Изменения должны касаться только выделенного фрагмента.

Если возможно, предложите два решения, одно – с использованием bind, другое – без него. Какое решение лучше?

Решение с bind

Первое решение – передать в ask функции с привязанным контекстом и аргументами.

"use strict";

function ask(question, answer, ok, fail) {
  var result = prompt(question, '');
  if (result.toLowerCase() == answer.toLowerCase()) ok();
  else fail();
}

var user = {
  login: 'Василий',
  password: '12345',

  loginDone: function(result) {
    alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
  },

  checkPassword: function() {
    ask("Ваш пароль?", this.password, this.loginDone.bind(this, true), this.loginDone.bind(this, false));
  }
};

user.checkPassword();

Решение с локальной переменной

Второе решение – это скопировать this в локальную переменную (чтобы внешняя перезапись не повлияла):

"use strict";

function ask(question, answer, ok, fail) {
  var result = prompt(question, '');
  if (result.toLowerCase() == answer.toLowerCase()) ok();
  else fail();
}

var user = {
  login: 'Василий',
  password: '12345',

  loginDone: function(result) {
    alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
  },

  checkPassword: function() {
    var self = this;
    ask("Ваш пароль?", this.password,
      function() {
        self.loginDone(true);
      },
      function() {
        self.loginDone(false);
      }
    );
  }
};

user.checkPassword();

Оба решения хороши, вариант с bind короче.