Ich habe eine Javascript-Klasse und jede Methode gibt ein Q
-Versprechen zurück. Ich möchte wissen, warum this
in method2
und method3
undefiniert ist. Gibt es einen richtigeren Weg, diesen Code zu schreiben?
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2)
.then(this.method3);
}
MyClass.prototype.method1 = function(){
// ...q stuff...
console.log(this.options); // logs "opts" object
return deferred.promise;
};
MyClass.prototype.method2 = function(method1resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
MyClass.prototype.method3 = function(method2resolve){
// ...q stuff...
console.log(this); // logs undefined
return deferred.promise;
};
Ich kann dies mit bind
beheben:
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2.bind(this))
.then(this.method3.bind(this));
}
Aber nicht ganz sicher, warum bind
notwendig ist. ist .then()
this
ausgeschaltet?
this
ist immer das Objekt, für das die Methode aufgerufen wird. Wenn Sie die Methode an then()
übergeben, rufen Sie sie jedoch nicht auf! Die Methode wird irgendwo gespeichert und später aufgerufen. Wenn Sie this
beibehalten möchten, müssen Sie dies folgendermaßen tun:
.then(() => this.method2())
oder wenn Sie es vor ES6 tun müssen, müssen Sie this
beibehalten,
var that = this;
// ...
.then(function() { that.method2() })
Promise-Handler werden standardmäßig im Kontext des globalen Objekts (window
) aufgerufen. Im strikten Modus (use strict;
) ist der Kontext undefined
. Dies passiert mit method2
und method3
.
;(function(){
'use strict'
Promise.resolve('foo').then(function(){console.log(this)}); // undefined
}());
;(function(){
Promise.resolve('foo').then(function(){console.log(this)}); // window
}());
Für method1
rufen Sie method1
als this.method1()
auf. Diese Art des Aufrufs ruft es im Kontext des this
-Objekts auf, das Ihre Instanz ist. Deshalb ist der Kontext in method1
die Instanz.
Grundsätzlich übergeben Sie eine Funktionsreferenz ohne Kontextreferenz. Der this
-Kontext wird auf verschiedene Weise bestimmt:
myObj.f()
aufrufen, wird myObj
der this
-Kontext sein. **.bind
und .apply
. Diese geben Sie explizit an, was der this
-Kontext ist. Diese haben immer Vorrang vor den beiden vorhergehenden.In Ihrem Beispiel übergeben Sie eine Funktionsreferenz, dh sie wird beim Aufruf als globale Funktion oder als Funktion ohne Kontext bezeichnet. Die Verwendung von .bind
löst dieses Problem auf, indem eine neue Funktion erstellt wird, in der this
explizit festgelegt ist.
* Dies gilt nur für den nicht strengen Modus. Im strikten Modus ist this
auf undefined
gesetzt.
** Angenommen, die von Ihnen verwendete Funktion wurde nicht manuell gebunden.
Eine Möglichkeit, wie Funktionen ihren Kontext (this
) erhalten, ist das Objekt, für das sie aufgerufen werden (weshalb method1
den richtigen Kontext hat - er wird für this
aufgerufen. Sie übergeben einen Verweis auf die Funktion selbst an then
. Sie können sich vorstellen, dass die Implementierung von then
ungefähr so aussieht:
function then( callback ) {
// assume 'value' is the recently-fulfilled promise value
callback(value);
}
In diesem Beispiel ist callback
eine Referenz auf Ihre Funktion. Es hat keinen Kontext. Wie Sie bereits bemerkt haben, können Sie dies umgehen, indem Sie die Funktion an einen Kontext binden, bevor Sie sie dann übergeben.