2012-07-09 13 views
7

Hala js oop üzerinde beni rahatsız eden bir sorunum var - Eminim kötü yapıyorum ama bunu nasıl yapacağımı anlayamıyorum. onun ben başvuru kaybetti muhtemelen "Bu" -Javascript OOP - bunu eşzamansız geri aramada kaybettim

Örneğin, ben bu kodu

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.'); 
     } 
    } 
} 

var Sorun "request.onloadend" fonksiyonunun bağlamından setToken işlev erişimi edemem olmasıdır.

Bu sorunun çözümü nedir? "Bu" varumu bir şekilde bu işlevin içeriğine geçirebilir miyim?

Teşekkürler!

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

cevap

4

birkaç vardır:

sadece dış kapsamda bir referansı yakalayabilir
+0

Sanırım diğeri daha doğrudan, kod minimum düzeyde değişti ve hangi sahte anahtar sözcüğün kullanılacağına karar vermenize gerek yok. Sadece söylüyorum. – Esailija

+0

@Esailija: Ben de, ne yazık ki pratik değeri tarayıcı uyumluluğu ile sınırlandırılmıştır. – Jon

+0

"XHR.onloaded" ile hareket noktası – Esailija

1

, ben tanımlayıcı self kullandım, ancak daha semantik anlam adını vermek çekinmeyin Bunu yapmanın yolları.

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.'); 
     } 
    } 
} 

bir başka yolu bind kullanmaktır:: en doğrudan basitçe size gereken değerin bir kopyasını kurtarmaktır

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); 

İkinci yaklaşım ise "süpürge", ancak tarayıcıya uyumluluk sorunları vardır (IE < 9 desteklemiyor). callback'inde önce

1

Yakalama this:

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 fonksiyonu: callback'inde dışında yerel bir var içinde

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

kaydet this.

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

Oldukça doğru: geri arama içerik olarak XMLHTTPRequest nesnenin (this yani değeri) olarak adlandırılır.

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: Eğer callback'inde kapsamında erişebilirsiniz böylece, senin örnek başka bir ad vermek gerekir. Benyerine authInstance kullandım, çünkü betimsel değişken isimleri kullanmak genelde iyi olur; authInstance'un ne anlama geldiğini öğrenmek zorunda kalmayacaksınız, ancak ileride birisi (muhtemelen siz!) kodu okurken self belirsiz olabilir.

Başka bir seçenek bind kullanmaktır, ancak bu muhtemelen burada gerekenden daha karmaşıktır.

+0

Kodun çoğunun değiştirilmesi ve 2 ayrı "anahtar sözcüğün" yanı sıra fazladan bir değişken kullanılması, sadece .bind (this) 'a atmaktan daha az karmaşıktır. son? – Esailija

+0

@Esailija Bence bind formu daha az sezgisel ve okunaklı. Bağlam, yalnızca işlevin sonunda netleşir ve işlev oldukça uzundur. İki satırlı bir işlev olsaydı, sana katılıyorum. – lonesomeday

+0

Sınıfın şu andaki örneğine atıfta bulunan bir sınıf içinde (bu, bağlamanın nasıl uygulandığı önemli değil) (http://en.wikipedia.org/wiki/Dynamic_dispatch)), benim düşüncemde daha sezgiseldir. Ama buna katılmayabiliriz. – Esailija