область при выполнении обратных вызовов JavaScript JavaScript - PullRequest
2 голосов
/ 14 января 2012

Люди - я пытаюсь научиться писать OO Javascript, я пришел из as3 OO background ... у меня проблема с передачей метода класса в качестве обратного вызова другому классу ...

в приведенном ниже примере я создаю экземпляр класса AppController, а в нем я создаю экземпляр класса ConnectionMonitor.Я передаю один из методов AppController, который будет вызван ConnectionMonitor.Обратный вызов работает нормально, но кажется, что то, что находится внутри функции обратного вызова, теряет область видимости своего класса (AppController) ...

какие-либо мысли?

//in the HTML
<script>
    $(document).ready( function(){
        new AppContoller().init();
    });
</script>


//in the js file

//AppController Class
var AppContoller = function(){
    this.body = $("body");

    this.init = function(){
        this.connection = new ConnectionMonitor();
        this.connection.detectInitialConnection( this.initialConnectionDetected );
    }

    //callback function I pass
    this.initialConnectionDetected = function(bool){
        if(bool){
            trace("app connected? "+bool); // logs - "app connected? true"
            this.showOnlineSwf();  //thows error - "Object [object DOMWindow] has no method 'showOnline' "
        }
        else{

        }
    }

    this.showOnlineSwf = function(){
        trace("i'm online");

    }

}

//ConnectionMonitor Class
var ConnectionMonitor = function()
{   
    this.detectInitialConnection = function(callbackFunction){
        setTimeout(callbackFunction, 1000, [true]);
    }
}




function trace(arg){
    console.log(arg.toString());
}

Ответы [ 5 ]

4 голосов
/ 14 января 2012

Измените init, чтобы привязать обратный вызов к исходному контексту:

this.init = function() {
    this.connection.detectInitialConnection(
        this.initialConnectionDetected.bind(this));
}

К сожалению, bind поддерживается не во всех браузерах , но вы можете захватить текущее значениеthis в замыкании для достижения аналогичного эффекта:

this.init = function() {
    var that = this;
    this.connection.detectInitialConnection(function(detected) {
        that.initialConnectionDetected(detected);
    });
}

Еще один подход - сделать detectInitialConnection способным обрабатывать необязательный параметр контекста:

this.detectInitialConnection = function(callbackFunction, _this){
    setTimeout(function() {
        callbackFunction.apply(_this || this, arguments);
    }, 1000, [true]);
}

You 'затем вызовите его так:

this.init = function() {
    this.connection.detectInitialConnection(
        this.initialConnectionDetected, this);
}

Цель каждого из этих примеров - сохранить ссылку на значение this из контекста, в котором был вызван detectInitialConnection.

2 голосов
/ 14 января 2012

это сложно в javascript, особенно в том, что касается конструкторов и передачи функций. Если вы сделаете это, это будет работать:

//AppController Class
var AppContoller = function(){
this.body = $("body");
var self = this;
this.init = function(){
    this.connection = new ConnectionMonitor();
    this.connection.detectInitialConnection( this.initialConnectionDetected );
}

//callback function I pass
this.initialConnectionDetected = function(bool){
    if(bool){
        trace("app connected? "+bool); // logs - "app connected? true"
        self.showOnlineSwf();
    }
    else{

    }
}

this.showOnlineSwf = function(){
    trace("i'm online");

}

}
2 голосов
/ 14 января 2012

setTimeout запустит переданную функцию, привязанную к window. Вы можете изменить это с помощью ES5 bind:

this.connection.detectInitialConnection( this.initialConnectionDetected.bind(this) );

Это не работает в старых браузерах, но предоставленная ссылка MDN имеет обходной путь.

1 голос
/ 14 января 2012

Другие ответы верны, но никто, кажется, не упоминает, что Function.prototype.bind поддерживается не во всех браузерах .Чтобы это сработало, вам нужно включить библиотеку Kris Kowal es5-shim .

1 голос
/ 14 января 2012

this.initialConnectionDetected передаст функцию, но без информации о том, что она должна выполняться в экземпляре.

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

Вы должны связать эту информацию (то есть значение this, которое является экземпляром), используя, например, .bind:

this.connection.detectInitialConnection(this.initialConnectionDetected.bind(this));

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

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