2012-06-08 15 views
8

nehme ich eine Funktion a haben:Wie passieren „dieses“ Fenster setInterval

function a() { 
    this.b = 1; 
    this.set = setInterval(function() {console.log(this.b);}, 200); 
} 

Also, wenn a.set() wird die anonyme Funktion aufgerufen wird aufgerufen. Aber das wird nicht funktionieren, da dies zu dem Zeitpunkt ist, an dem die Funktion ausgelöst wird, auf das Fensterobjekt zeigt. Es ist auch keine gute Idee a.b zu verwenden, da es mehrere Instanzen von a gibt.

Was ist eine gute Lösung für dieses Problem?

+0

Warum verwenden Sie nicht "apply" oder "call" https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply – Deeptechtons

+0

@Deeptchtons - ich glaube nicht, "apply" oder 'call' ist für dieses Problem nützlich, aber vielleicht könnten Sie erklären, was Sie in einer Antwort vorhatten? – nnnnnn

+0

@nnnnnn Frage ist definitiv ein Kandidat für "Wie ändere ich Kontext innerhalb der Funktion" Art der Frage. Welches wird mit appy oder Anruf gelöst. Aber könnte für diesen Fall übertrieben sein. – Deeptechtons

Antwort

16

Shop ein Verweis auf this:

function a() { 
    var self = this; 
    self.b = 1; 
    self.set = setInterval(function() {console.log(self.b);}, 200); 
} 

Die anonyme Funktion, die Sie setInterval geben hat Zugriff auf alle Variablen in seiner enthaltenden Bereich, das heißt, alle lokalen Variablen von function a(). Die Magie von JS-Verschlüssen hält diese Variablen am Leben, selbst nachdem a() abgeschlossen wurde und jeder Aufruf von a() seine eigene Schließung erhält.

+0

Ja, ich habe solche Beispiele gesehen, aber genau das macht mich verwirrt. Angenommen, "a" endet, bevor das Ereignis bei 200ms ausgelöst wird, scheint das variable Selbst zu diesem Zeitpunkt zerstört zu werden. Wenn nicht, dann wenn es zerstört würde? nach dem Intervall wird gelöscht? – NSF

+0

Wie ich in meiner Antwort erwähnt habe, hat eine innere Funktion Zugriff auf Variablen im Rahmen ihrer enthaltenden Funktion - selbst nachdem die enthaltende Funktion beendet ist. In diesem Fall enthält 'setInterval' weiterhin einen Verweis auf die innere Funktion, so dass sie sie auch dann aufrufen kann, wenn' a() 'beendet ist; bis das Intervall gelöscht ist, bleibt diese Referenz am Leben und die Variablen bleiben am Leben. Beachten Sie, dass 'a()' _definitely_ endet, bevor das Intervall ausgelöst wird (egal wie kurz das Intervall ist), da JS in einem einzelnen Thread ausgeführt wird. Google "JavaScript closures" für weitere Informationen. – nnnnnn

+0

Sinn machen. Vielen Dank. – NSF

2

Speichern Sie einfach Ihre this Referenz in einer anderen Variablen, die nicht von der window -call später überschrieben wird. Später können Sie diese Variable verwenden, um auf das Objekt zu verweisen, mit dem Sie begonnen haben.

function a() { 
    this.b = 1; 
    var that = this; 
    this.set = setInterval(function() {console.log(that.b);}, 200); 
} 
0

In Ihrem Fall können Sie einfach:

function a() { 
    var _this = this; 
    this.b = 1; 
    this.set = setInterval(function() { 
     console.log(_this.b); 
    }, 200); 
} 

Normalerweise können wir auch eine Hilfsmethode Function.prototype.bind zu fix die this Referenz.

4

Dies wäre die sauberste Lösung, da die meiste Zeit tatsächlich schalten Sie ruft die diesen Kontext für Ihre aufeinander folgenden Methode wollen:

// store scope reference for our delegating method 
    var that = this; 
    setInterval(function() { 
     // this would be changed here because of method scope, 
     // but we still have a reference to that 
     OURMETHODNAME.call(that); 
    }, 200); 
3

Da wir ES6 jetzt haben, denke ich, müssen wir eine andere Antwort hier :

einen Pfeil Funktion verwenden:

function a() { 
    this.b = 1; 
    this.set = setInterval(() => {console.log(this.b);}, 200); 
} 

Pfeil Funktionen, haben gegenüber normalen Funktionen, keine this Zusammenhang auf ihre besitzen. Dies bedeutet, dass Sie Zugriff auf die äußere this haben.

+1

ES6 hat meine Syntax wieder auf fast nichts reduziert! Vielen Dank! – HoldOffHunger