Невозможно использовать "классовые" методы для обратных вызовов в JavaScript - PullRequest
6 голосов
/ 26 октября 2010

У меня действительно тяжелое время, когда я заворачиваюсь в прототипы на JavaScript.

Раньше у меня были проблемы с вызовом что-то вроде этого:

o = new MyClass();
setTimeout(o.method, 500);

и мне сказали, что я могу это исправить, используя:

setTimeout(function() { o.method(); }, 500);

И это работает. Теперь у меня другая проблема, и я подумал, что могу решить ее таким же образом, просто добавив анонимную функцию. Моя новая проблема заключается в следующем:

MyClass.prototype.open = function() {
    $.ajax({
        /*...*/
        success: this.some_callback,
    });
}

MyClass.prototype.some_callback(data) {
    console.log("received data! " + data);
    this.open();
}

Я обнаружил, что в теле MyClass.prototype.some_callback ключевое слово this относится не к экземпляру MyClass, к которому был вызван метод, а к тому, что выглядит как запрос jQuery ajax (это объект, который, помимо прочего, содержит объект xhr и все параметры моего вызова ajax).

Я пытался сделать это:

$.ajax({
    /* ... */
    success: function() { this.some_callback(); },
});

но я получаю ошибку:
Uncaught TypeError: Object #<an Object> has no method 'handle_response'

Я не уверен, как правильно это сделать. Я новичок в JavaScript, и концепция прототипов, которые иногда ведут себя как классы, но обычно не делают, меня действительно смущает.

Так каков правильный способ сделать это? Пытаюсь ли я принудить JavaScript к парадигме, которой он не принадлежит?

1 Ответ

16 голосов
/ 26 октября 2010

Пытаюсь ли я заставить JavaScript создать парадигму, которой он не принадлежит?

Когда вы говорите о классах, да.

ИтакКак правильно это сделать?

Прежде всего, вы должны узнать, какие значения может содержать ключевое слово this.

  1. Простой вызов функции

    myFunc(); - this будет ссылаться на глобальный объект (он же window) [1]

  2. Вызов функции как свойства объекта (он же метод)

    obj.method(); - this будет ссылаться на obj

  3. Вызов функции вместе с новым оператором

    new MyFunc(); - this будет ссылаться на создаваемое new instance

Теперь давайте посмотрим, как это применимона ваш случай:

MyClass.prototype.open = function() {
    $.ajax({ // <-- an object literal starts here
        //...
        success: this.some_callback,  // <- this will refer to that object
    });      // <- object ends here
}

Если вы хотите вызвать метод some_callback текущего экземпляра, вам следует сохранить ссылку на этот экземпляр (в простую переменную).

MyClass.prototype.open = function() {
    var self = this; // <- save reference to the current instance of MyClass
    $.ajax({ 
        //...
        success: function () {
            self.some_callback();  // <- use the saved reference
        }                          //    to access instance.some_callback
    });                             
}

[1] обратите внимание, что в новой версииn (ES 5 Str.) В случае 1 значение this будет равно undefined

[2] В еще одном случае вы используете call или apply для вызова функции с заданным this

...