Отложенные изменения JQuery "this"

Я пытаюсь, чтобы объект javascript запускал отложенный метод, и когда он .done() вызывает функцию в том же самом объекте. У меня проблемы, потому что "this" становится отложенным объектом вместо объекта, который его вызвал.

PageObject.prototype.successFunction = function() {
  console.log(arguments);
  return console.log(this.name + " Success function called");
};

PageObject.prototype.loadPage = function(url) {
  return $.when($.mobile.loadPage("pages/" + url))
    .done(this.successFunction);
};

var pg = new PageObject();
pg.loadPage("test.html");

Как отправить "this" в функцию successFunction? Этот объект PageObject также будет расширен другими, поэтому знание "this" при запуске successFunction будет очень удобным.

Кажется простым и, вероятно, имеет простой ответ. Я смотрел в .apply(), но я не уверен, что это помогло. Этот пост при переполнении стека был полезен немного, но он сломался, как только я положил его в функцию .done().

Функции как параметры (с параметрами) - JavaScript

Ответ 1

jQuery proxy вернет функцию, привязанную к определенному контексту:

PageObject.prototype.loadPage = function(url) {
  return $.when($.mobile.loadPage("pages/" + url))
    .done($.proxy(this.successFunction, this));
};

Существует также ES5 bind, который работает аналогичным образом, но его нужно подкрепить в старых браузерах.

PageObject.prototype.loadPage = function(url) {
  return $.when($.mobile.loadPage("pages/" + url))
    .done(this.successFunction.bind(this));
};

apply и call могут немедленно выполнять функцию с указанным контекстом, но proxy и bind возвращают функцию, которая может быть использована позже или передана другим функциям.

Ответ 2

this "переменная" в JavaScript называется "вызывающим объектом" и определяется, когда вызывается ее встроенная функция (а не когда она определена). Его можно установить несколькими способами:

  • Вы можете установить его с помощью оператора . (например, myObject.myFunction())
  • Вы можете установить его с помощью методов call() или apply()
  • Вы можете (под ES5) связывать его постоянно, используя метод bind()
  • Он будет по умолчанию глобальным объектом, если ни один из вышеперечисленных методов не установит его в нечто другое

Важно понять, что (помимо метода 3 выше), все это о том, как вызывается функция при вызове, а не о том, как она ссылается, а не о том, как она хранится, а не о том, где она была создана.

В вашем случае вы передаете this.successFunction в качестве ссылки на функцию, которую должен вызывать jQuery, но он не называет его таким образом (потому что он просто получил ссылку на функцию, а не какую-либо информацию о том, как это функция должна быть вызвана).

Есть несколько причудливых трюков, которые вы можете использовать с методами jQuery $.proxy() или ES5 .bind(), но когда дело доходит до него, самый простой способ справиться с этим - просто сохранить this и использовать оболочку функции:

PageObject.prototype.loadPage = function(url) {
    var self = this;
    return $.when($.mobile.loadPage("pages/" + url))
            .done(function () { self.successFunction(); });
};

Обратите внимание, что мы используем метод 1 для явного привязки successFunction вызывающего объекта к тому же, что и вызывающий объект loadPage. Он короткий, простой, понятный, отлично работает под ES3 и не зависит от jQuery.