【问题标题】:Why is 'this' undefined inside class method when using promises? [duplicate]为什么在使用 Promise 时在类方法中未定义“this”? [复制]
【发布时间】:2016-04-28 02:42:20
【问题描述】:

我有一个 javascript 类,每个方法都返回一个 Q 承诺。我想知道为什么thismethod2method3 中未定义。有没有更正确的方法来编写这段代码?

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 关闭了吗?

【问题讨论】:

  • 当您使用 bind() 时,它会创建另一个函数,其范围与您将通过参数传递的范围完全相同。虽然它只回答了您的最后一个问题,但请查看 Mozila 的文档:developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
  • 用 8 个词解释 this 是如何与 that 重复的?我刚刚提出了同样的问题,that 回答。我已经知道that,但我正在接受承诺、ES6 类和this
  • @Paulpro 不太确定这应该被标记为setTimeout issue 的副本;因为问题以两种完全不同的方式出现。希望在 Promise 的上下文中解决他们的this 范围问题的人们会立即被指向一个更间接的问题,其中接受的答案使用 2009 年的反模式。2 + 2 = 4 !== ((8+2)*6)/15 = 4
  • IMO 绝对不应该被标记为重复,尤其是关于超时的问题。这个问题专门关于 Promises 和答案是上帝派来的。谢谢。

标签: javascript node.js promise this q


【解决方案1】:

this 始终是调用该方法的对象。但是,当将方法传递给then() 时,您并没有调用它!该方法将存储在某个地方并稍后从那里调用。如果你想保留this,你必须这样做:

.then(() => this.method2())

或者如果你必须使用pre-ES6的方式,你需要保留this之前:

var that = this;
// ...
.then(function() { that.method2() })

【讨论】:

  • 很好的答案 - 或 pre-ES6 ".then(this.method2.bind(this))"
  • 我用过.then(data => this.method(data))
  • FAR FAR 更简单的方法:.then(( foo = this) => {... //然后使用 foo 而不是 this [也转换为 es6 之前的版本] 只要确保它不是覆盖!
  • 被低估的解释,在设置 Promise 时遇到了很多困难,现在是 fixex。谢谢
【解决方案2】:

默认情况下,Promise 处理程序在全局对象 (window) 的上下文中调用。当处于严格模式 (use strict;) 时,上下文为 undefined。这就是 method2method3 发生的事情。

;(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是一个帮助我理解it的答案。
【解决方案3】:

基本上,您传递给它的是一个没有上下文引用的函数引用。 this 上下文通过以下几种方式确定:

  1. 隐式。调用全局函数或没有绑定的函数假定全局上下文。*
  2. 直接参考。如果您调用myObj.f(),那么myObj 将成为this 上下文。**
  3. 手动绑定。这是您的函数类,例如.bind.apply。这些您明确说明this 上下文是什么。这些总是优先于前两个。

在您的示例中,您传递了一个函数引用,因此在调用它时,它暗示它是一个全局函数或一个没有上下文的函数。使用 .bind 通过创建一个新函数来解决这个问题,其中 this 被显式设置。

*这只适用于非严格模式。在严格模式下,this 设置为 undefined

**假设你使用的函数没有被手动绑定。

【讨论】:

    【解决方案4】:

    函数获取其上下文 (this) 的一种方式是来自调用它们的对象(这就是为什么 method1 具有正确的上下文 - 它是在 this 上调用的)。您将对函数本身的引用传递给then。你可以想象then 的实现看起来是这样的:

    function then( callback ) {
    
      // assume 'value' is the recently-fulfilled promise value
      callback(value);
    }
    

    在该示例中,callback 是对您的函数的引用。它没有任何上下文。正如您已经注意到的,您可以通过在将函数传递给 then 之前将函数绑定到上下文来解决这个问题。

    【讨论】:

      猜你喜欢
      • 2018-11-17
      • 2016-09-26
      • 2016-11-30
      • 1970-01-01
      • 2012-08-01
      • 2011-04-30
      • 2022-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多