Вызвать метод объекта JavaScript из обратного вызова - PullRequest
19 голосов
/ 08 августа 2011

Я определяю следующее MyClass и его методы в пользовательском скрипте:

function MyClass() {
    this.myCallback = function() {
        alert("MyClass.myCallback()");
    };

    this.startRequest = function() {
        GM_xmlhttpRequest({
            'method': 'GET',
            'url': "http://www.google.com/",
            'onload': function (xhr) {
                myClassInstance.myCallback();
            }
        });
    };
}

var myClassInstance = new MyClass();
myClassInstance.startRequest();

Этот скрипт работает, и метод myCallback() вызывается после завершения GM_xmlhttpRequest .

Однако это работает только потому, что обратный вызов onload ссылается на глобальную переменную myClassInstance. Если я обновлю обратный вызов onload на

'onload': function (xhr) {
    this.myCallback();
}

Тогда я получаю (Chrome) ошибку:

Uncaught TypeError: Объект [объект DOMWindow] не имеет метода myCallback.

Кажется, this оценивается не в том контексте.

Есть ли способ вызвать myCallback() метод myClassInstance, не прибегая к использованию глобальной переменной?

Ответы [ 3 ]

31 голосов
/ 08 августа 2011

Сохраните правильный this, когда он находится в области видимости, в переменную.Тогда вы можете сослаться на это позже:

 this.startRequest = function() {
     var myself = this;
     GM_xmlhttpRequest({
         'method': 'GET',
         'url': "http://www.google.com/",
         'onload': function (xhr) {
             myself.myCallback();
         }
     });
 };
6 голосов
/ 08 августа 2011

Самое простое решение, как уже указывалось, это создание псевдонима для this, который остается в области видимости.Наиболее популярными именами переменных для псевдонима являются такие вещи, как self или that, но на самом деле все работает.

Другая альтернатива (которая может или не может быть лучше, в зависимости от варианта использования)связывание метода в «простую» функцию и использование его вместо этого:

var f = this.callback.bind(this);

...
'onload': function(){
    f();
}

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

3 голосов
/ 08 августа 2011

Сохраните ссылку на экземпляр и используйте ее:

function MyClass() {
    this.myCallback = function() {
        alert("MyClass.myCallback()");
    };

    var instance = this;

    instance.startRequest = function() {
        GM_xmlhttpRequest({
            'method': 'GET',
            'url': "http://www.google.com/",
            'onload': function (xhr) {
                instance.myCallback();
            }
        });
    };
}
...