Javascript setTimeout内部的变量表示它未定义,但外部的变量表示它已定义

Javascript setTimeout内部的变量表示它未定义,但外部的变量表示它已定义,javascript,angular,Javascript,Angular,我有课。我需要在超时时间内完成一些http工作。我面临的问题是超时内的http变量一直说它未定义 export class MyClass { http:Http: constructor(private http:Http) { this.http = http; } sendFriendRequest(){ this.http.post( ...//http variable is defined here

我有课。我需要在超时时间内完成一些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
        }
   }
}

您应该在这里使用箭头函数,以保留此函数的存在

setTimeout(()=>{
   this.http.post(...  //http is not defined here
})
这样做时,
函数内部的这个
被绑定到外部上下文。这与:

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

使用
function(){…

解决此问题最常用的两种方法:

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

2) 使用箭头函数

this.http.post( ...//http variable is defined here
           setTimeout(() => {
               that.http.post(...  //http is not defined here
        }
   }
第一种方法是旧的ES5,您不需要任何编译器,对于ES6版本(#2),您需要使用类似babel的东西


有关arrow函数和babel的更多信息,请参见此处:

原因是setTimeout中的回调函数位于不同的词法环境中。这就是为什么在ES6+中可以使用
=>
定义函数。这样,函数中的代码与函数共享相同的范围

要解决这个问题,您可以使用ES6+语法,其中使用
(a,b,args){…}
而不是
(a,b,args)=>{…}

setTimeout(() => {
  this.http.post(...);
});
或使用ES5语法:

var root = this;

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

希望这能有所帮助!

在JavaScript中,
这个
关键字用于访问调用函数的
上下文。JavaScript中的函数总是使用上下文调用,无论您使用
.methodName()调用它们
语法或不带语法,除非在当前作用域中设置了
'use strict'
标志

setTimeout(() => {
    // Hey I can access 'this' in here!
}, 1000);
在没有如下上下文的情况下调用函数时:

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

注意:当ES6与Babel这样的transpiler一起使用时,默认情况下在输出中设置严格模式

在对象上保存对函数的引用时,可以使用点语法将对象作为“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有一个。

这是因为
这个
上下文:我们真的需要4个答案来回答这个问题吗?这些答案本质上都是说“使用箭头函数来获得适当的
这个
上下文”?@MarkRajcok是的,只有3个答案是不够的!谢谢你的回答!完美的答案加上解释+1:)谢谢你的信息!如果在第二个示例中我们用箭头函数替换
函数()
,它会起作用吗?如果不会,为什么?