【问题标题】:Variable inside setTimeout says it is undefined, but when outside it is defined [duplicate]setTimeout 内部的变量表示它未定义,但在外部时它已定义[重复]
【发布时间】:2016-07-12 14:38:26
【问题描述】:

我有课。我需要在超时内做一些 http 工作。我面临的问题是超时内的http变量一直说它是未定义的。

export class MyClass {

    http:Http:

    constructor(private http:Http) {
        this.http = http;
    }

    sendFriendRequest(){

    this.http.post( ...//http variable is defined here
           setTimeout(function(){
               this.http.post(...  //http is not defined here
        }
   }
}

【问题讨论】:

  • 这是因为this 上下文:stackoverflow.com/questions/2130241/…
  • 我们真的需要 4 个答案来回答这个问题吗?基本上都说“使用箭头函数来获得正确的 this 上下文”?
  • @MarkRajcok 是的,只有 3 个答案是不够的!

标签: angular typescript


【解决方案1】:

原因是 setTimeout 内部的回调函数处于不同的词法环境。这就是为什么在 ES6+ 中可以使用 => 定义函数的原因。这是为了让函数内的代码与函数共享相同的作用域。

要解决此问题,您可以使用 ES6+ 语法,而不是 function(a,b,args){...},您可以使用 (a,b,args) => {...}

setTimeout(() => {
  this.http.post(...);
});

或者使用 ES5 语法:

var root = this;

setTimeout(function(){
    root.http.post(...);
});

希望这会有所帮助!

【讨论】:

  • 如果在第二个示例中我们将function() 替换为箭头函数() =>,它会起作用吗?如果不是,为什么?
【解决方案2】:

在 JavaScript 中,this 关键字用于访问调用函数的context。无论您使用 .methodName() 语法还是不使用它,JavaScript 中的函数总是在上下文中调用,除非在当前范围内设置了 'use strict' 标志。

当一个函数在没有这样的上下文的情况下被调用时:

myFunction()

运行时假定上下文是全局窗口对象(除非设置了'use strict' 标志,在这种情况下上下文将未定义。)

注意:当使用 ES6 和 Babel 等转译器时,输出中默认设置严格模式。

当对函数的引用保存在对象上时,您可以使用点语法将该对象作为“this”的上下文来调用该函数。

var myObj = {
    myFunc: function(){}
};

// myFunc invoked like this, the value of 'this' inside myFunc will be myObj.
myObj.myFunc();

操纵“这个”:

致电并申请

您始终可以通过使用 .call 或 .apply 方法调用函数来更改函数的上下文。在这种情况下,您有一个匿名函数,它不是由您调用的,而是由 setTimeout 函数调用的。因此,您将无法利用 .call 或 .apply。

绑定

相反,您可以使用 .bind 方法创建一个具有自定义上下文的新函数。通过在您的匿名函数上调用 .bind() ,将返回一个新函数,该函数将您的自定义上下文绑定到“this”。这样您就可以将自定义绑定函数作为数据传递给 setTimeout。

setTimeout(function(){
   // your code.
}.bind(this), 1000);

现在在匿名函数中,“this”关键字将绑定到正确的值。

词汇“this”:

然而,在 ES6 中,当使用 箭头函数 时,关于“this”的规则会发生变化。如果您使用此语法,您将看到“this”的上下文将与当前范围内的任何内容保持一致。

setTimeout(() => {
    // Hey I can access 'this' in here!
}, 1000);

保存参考:

如果您查看 Babel 的编译输出,您会看到 Babel 通过使用 _this1、_this2 等保存对“this”的引用来跟踪上下文。

要自己使用此方法,只需声明一个新变量(通常使用 'that' 或 'self' )并在匿名函数中使用它访问值,如下所示:

var self = this;
setTimeout(function(){
    self.http.post...
}); 

希望这会有所帮助。

更多解释 developer.mozilla.org 有一个good article describing the behavior of 'this' inside a functions scope

【讨论】:

  • 感谢您的好评!
  • 完美答案+1 :)
【解决方案3】:

你应该在这里使用箭头功能,以保持 this 的存在。

setTimeout(()=>{
   this.http.post(...  //http is not defined here
})

这样做时,函数内部的this 绑定到外部上下文。同理:

setTimeout(function(){
    this.http.post();
}.bind(this));

【讨论】:

    【解决方案4】:

    当您使用function(){... 时,setTimeout 内部的this 不一样

    解决此问题的 2 种最流行的方法:

    1) 使用额外的变量存储在“this”之外

    var that = this;
    this.http.post( ...//http variable is defined here
               setTimeout(function(){
                   that.http.post(...  //http is not defined here
            }
       }
    

    2) 使用箭头函数

    this.http.post( ...//http variable is defined here
               setTimeout(() => {
                   that.http.post(...  //http is not defined here
            }
       }
    

    第一种方式是旧的 ES5,你不需要任何编译器,对于 ES6 版本(#2)你需要使用类似 babel 的东西。

    在此处了解有关箭头函数和 babel 的更多信息:https://babeljs.io/docs/learn-es2015/

    【讨论】:

    • 感谢您的信息!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-22
    • 1970-01-01
    • 2014-10-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-16
    • 1970-01-01
    相关资源
    最近更新 更多