为什么在使用 promises 时 'this' 未在 class 方法中定义?
Why is 'this' undefined inside class method when using promises?
我有一个 javascript class,每个方法 returns 一个 Q
承诺。我想知道为什么 this
在 method2
和 method3
中未定义。这段代码有没有更正确的写法?
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;
};
我可以使用 bind
:
来解决这个问题
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2.bind(this))
.then(this.method3.bind(this));
}
但不完全确定为什么 bind
是必要的; .then()
杀死 this
了吗?
函数获取其上下文 (this
) 的一种方式是从调用它们的对象中获取(这就是为什么 method1
具有正确的上下文 - 它是在 this
上调用的) .您正在将函数本身的引用传递给 then
。你可以想象 then
的实现看起来像这样:
function then( callback ) {
// assume 'value' is the recently-fulfilled promise value
callback(value);
}
在该示例中,callback
是对您的函数的引用。它没有任何上下文。正如您已经注意到的那样,您可以通过在将函数传递给 then 之前将函数绑定到上下文来解决这个问题。
this
始终是调用该方法的对象。但是,当将方法传递给 then()
时,您并没有调用它!该方法将存储在某个地方并稍后从那里调用。如果你想保留 this
,你必须这样做:
.then(() => this.method2())
或者如果你必须以 ES6 之前的方式来做,你需要在
之前保留 this
var that = this;
// ...
.then(function() { that.method2() })
默认情况下,在全局对象 (window
) 的上下文中调用 Promise 处理程序。在严格模式下 (use strict;
),上下文是 undefined
。这就是 method2
和 method3
.
正在发生的事情
;(function(){
'use strict'
Promise.resolve('foo').then(function(){console.log(this)}); // undefined
}());
;(function(){
Promise.resolve('foo').then(function(){console.log(this)}); // window
}());
对于 method1
,您将 method1
称为 this.method1()
。这种调用它的方式在作为您的实例的 this
对象的上下文中调用它。这就是为什么 method1
中的上下文是实例。
基本上,您向它传递了一个没有上下文引用的函数引用。 this
上下文通过几种方式确定:
- 隐含地。调用全局函数或没有绑定的函数假定全局上下文。*
- 通过直接引用。如果您调用
myObj.f()
,那么 myObj
将成为 this
上下文。**
- 手动装订。这是您 class 的功能,例如
.bind
和 .apply
。这些你明确说明 this
上下文是什么。这些总是优先于前两个。
在您的示例中,您正在传递一个函数引用,因此在调用它时暗示它是一个全局函数或没有上下文的函数。使用 .bind
通过创建一个明确设置 this
的新函数来解决此问题。
*这仅适用于 non-strict 模式。在严格模式下,this
设置为 undefined
.
**假设您使用的函数没有被手动绑定。
我有一个 javascript class,每个方法 returns 一个 Q
承诺。我想知道为什么 this
在 method2
和 method3
中未定义。这段代码有没有更正确的写法?
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;
};
我可以使用 bind
:
function MyClass(opts){
this.options = opts;
return this.method1()
.then(this.method2.bind(this))
.then(this.method3.bind(this));
}
但不完全确定为什么 bind
是必要的; .then()
杀死 this
了吗?
函数获取其上下文 (this
) 的一种方式是从调用它们的对象中获取(这就是为什么 method1
具有正确的上下文 - 它是在 this
上调用的) .您正在将函数本身的引用传递给 then
。你可以想象 then
的实现看起来像这样:
function then( callback ) {
// assume 'value' is the recently-fulfilled promise value
callback(value);
}
在该示例中,callback
是对您的函数的引用。它没有任何上下文。正如您已经注意到的那样,您可以通过在将函数传递给 then 之前将函数绑定到上下文来解决这个问题。
this
始终是调用该方法的对象。但是,当将方法传递给 then()
时,您并没有调用它!该方法将存储在某个地方并稍后从那里调用。如果你想保留 this
,你必须这样做:
.then(() => this.method2())
或者如果你必须以 ES6 之前的方式来做,你需要在
之前保留this
var that = this;
// ...
.then(function() { that.method2() })
默认情况下,在全局对象 (window
) 的上下文中调用 Promise 处理程序。在严格模式下 (use strict;
),上下文是 undefined
。这就是 method2
和 method3
.
;(function(){
'use strict'
Promise.resolve('foo').then(function(){console.log(this)}); // undefined
}());
;(function(){
Promise.resolve('foo').then(function(){console.log(this)}); // window
}());
对于 method1
,您将 method1
称为 this.method1()
。这种调用它的方式在作为您的实例的 this
对象的上下文中调用它。这就是为什么 method1
中的上下文是实例。
基本上,您向它传递了一个没有上下文引用的函数引用。 this
上下文通过几种方式确定:
- 隐含地。调用全局函数或没有绑定的函数假定全局上下文。*
- 通过直接引用。如果您调用
myObj.f()
,那么myObj
将成为this
上下文。** - 手动装订。这是您 class 的功能,例如
.bind
和.apply
。这些你明确说明this
上下文是什么。这些总是优先于前两个。
在您的示例中,您正在传递一个函数引用,因此在调用它时暗示它是一个全局函数或没有上下文的函数。使用 .bind
通过创建一个明确设置 this
的新函数来解决此问题。
*这仅适用于 non-strict 模式。在严格模式下,this
设置为 undefined
.
**假设您使用的函数没有被手动绑定。