2012-07-09 10 views
7

Mam problem, który wciąż przeszkadza mi w js oop - jestem pewien, że robię to źle, ale nie mogę dostać, jak to zrobić dobrze.JavaScript OOP - zgubiłem to w asynchronicznym wywoływaniu zwrotnym

Na przykład, mam ten kod

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

Problemem jest to, że nie mogę dostęp funkcjonować setToken od kontekście funkcji „request.onloadend” - jego prawdopodobnie dlatego, że stracił odniesienie do „tego”.

Co to jest rozwiązanie tego problemu? Czy mogę w jakiś sposób przekazać "ten" var do kontekstu tej funkcji?

Dzięki!

Odpowiedz

4

Istnieje kilka sposoby, aby to zrobić. Najbardziej bezpośredni jest po prostu zapisać kopię wartości, czego potrzebujesz:

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var self = this; // save "this" value 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); // use saved "this" value 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

Innym sposobem jest użycie bind:

request.onloadend = (function() { 
    var response = JSON.parse(request.responseText); 

    console.log(response); 
    if(response.result == 'found') { 
    var token = response.token; 

    this.setToken(token); // use saved "this" value 
    this.isSigned = true; 
    } else { 
    console.log('Not logged yet.'); 
    } 
}).bind(this); 

Drugie podejście jest „czystszy”, ale ma problemy z kompatybilnością przeglądarek (IE < 9 nie obsługuje tego).

+0

Myślę, że druga jest bardziej bezpośrednia, kod jest minimalnie zmieniony i nie musisz decydować, którego pseudo słowa kluczowego użyć. Tylko mówię. – Esailija

+0

@Eailailija: Ja też, ale niestety jego praktyczna wartość jest ograniczona przez kompatybilność przeglądarki. – Jon

+0

Punkt kontrolny z 'XHR.onloaded' – Esailija

1

można uchwycić tylko odniesienie do niej w zakresie zewnętrznym, Użyłem identyfikator self jednak prosimy podać nazwę bardziej semantyczne znaczenie:

var self = this; 
request.onloadend = function() { 
    ... 
    self.setToken(token); 
    ... 
}; 
1

Przechwytywanie this przed zwrotnego:

Auth.prototype.auth = function() { 
    var self = this; 

    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     self.setToken(token); 
     self.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
2

.bind funkcja:

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     this.setToken(token); 
     this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    }.bind(this); //<-- bound 
} 
0

Zapisz this w lokalnej var poza zwrotnego.

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(); 
    var _this = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     _this.setToken(token); 
     _this.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 
0

Jesteś dość rację: zwrotna jest wywoływana z obiektu XMLHTTPRequest jako kontekst (czyli wartość this). Musisz podać swoje wystąpienie inną nazwę, dzięki czemu można uzyskać do niego dostęp w ramach zwrotnego:

Auth.prototype.auth = function() { 
    var request = new XMLHttpRequest(), 
     authInstance = this; 

    request.open('GET', this.getAuthServerURL() + '/token', true); 
    request.send(); 

    request.onloadend = function() { 
     var response = JSON.parse(request.responseText); 

     console.log(response); 
     if(response.result == 'found') { 
     var token = response.token; 

     authInstance.setToken(token); 
     authInstance.isSigned = true; 
     } else { 
     console.log('Not logged yet.'); 
     } 
    } 
} 

See this answer to another question for more explanation of why this is necessary. Użyłem raczej authInstance niż self, ponieważ myślę, że ogólnie dobrze jest używać opisowych nazw zmiennych; nigdy nie będziesz musiał się zastanawiać, co oznacza authInstance, a self może być niejednoznaczne, gdy ktoś w przyszłości (prawdopodobnie ty!) odczyta kod.

Inną opcją jest użycie bind, ale jest to prawdopodobnie bardziej skomplikowane niż to konieczne tutaj.

+0

Modyfikowanie większości kodu i używanie 2 oddzielnych" słów kluczowych "oraz dodatkowej zmiennej jest mniej skomplikowane niż zwykłe wyrzucanie' .bind (this) ' koniec? – Esailija

+0

@Eailailija Myślę, że forma "bind" jest mniej intuicyjna i czytelna. Kontekst staje się jasny dopiero na końcu funkcji, a funkcja jest dość długa. Gdyby to była funkcja dwuliniowa, zgadzam się z tobą. – lonesomeday

+0

Wewnątrz klasy "this" odnoszące się do bieżącej instancji klasy ([bez względu na sposób implementacji powiązania] (http://en.wikipedia.org/wiki/Dynamic_dispatch)), jest w mojej opinii bardziej intuicyjne. Ale możemy się z tym nie zgodzić. – Esailija

Powiązane problemy