Variable inside setTimeout says it is undefined, but when outside it is defined
我要上课。我需要在超时内做一些HTTP工作。我面临的问题是超时内的HTTP变量一直说它是未定义的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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中的回调函数在不同的词汇环境中。这就是为什么在ES6+中可以使用
要解决这个问题,您可以使用es6+语法,其中使用
1 2 3 | setTimeout( () => { this.http.post(...) }); |
或使用ES5语法:
1 2 3 4 5 | var root = this; setTimeout(function(){ root.http.post(...) } |
希望这有帮助!
在javascript中,
当在没有类似上下文的情况下调用函数时:
1 | myFunction() |
上下文由运行时假定为全局窗口对象(除非设置了
注意:当对Babel这样的蒸腾器使用ES6时,在输出中默认设置严格模式。
当对函数的引用保存在对象上时,可以使用点语法以对象作为"this"的上下文来调用该函数。
1 2 3 4 5 6 | var myObj = { myFunc: function(){} }; // myFunc invoked like this, the value of 'this' inside myFunc will be myObj. myObj.myFunc(); |
操纵"this":
调用与应用
您可以通过使用.call或.apply方法调用函数来更改其上下文。在这种情况下,您有一个匿名函数,它不是由您调用的,而是由setTimeout函数调用的。正因为如此,你将无法利用。打电话或。申请。
束缚
相反,您可以使用.bind方法创建一个具有自定义上下文的新函数。通过对匿名函数调用.bind(),将返回一个新函数,该函数将您的自定义上下文绑定到"this"。这样就可以将自定义绑定函数作为数据传递给setTimeout。
1 2 3 | setTimeout(function(){ // your code. }.bind(this), 1000); |
现在,在匿名函数内部,"this"关键字将绑定到正确的值。
词汇"这个":
但是,在ES6中,使用箭头函数时,有关"this"的规则会发生更改。如果使用此语法,您将看到"this"的上下文将保持与当前作用域中的上下文相同。
1 2 3 | setTimeout(() => { // Hey I can access 'this' in here! }, 1000); |
保存引用:
如果您查看babel编译的输出,您将看到babel通过保存对"this"的引用来跟踪上下文,其中包括"this1"、"this2"等等。
要使用此方法,只需声明一个新变量(通常使用"that"或"self"),并在匿名函数中使用它访问值,如下所示:
1 2 3 4 | var self = this; setTimeout(function(){ self.http.post... }); |
希望这有帮助。
为了得到更多的解释,developer.mozilla.org有一篇很好的文章描述了函数范围内"this"的行为。
您应该在这里使用arrow函数,以保持这个函数的存在。
1 2 3 | setTimeout(()=>{ this.http.post(... //http is not defined here }) |
这样,函数内部的
1 2 3 | setTimeout(function(){ this.http.post(); }.bind(this)); |
使用
本期最流行的两种方式:
1)使用额外变量存储在"this"之外
1 2 3 4 5 6 | var that = this; this.http.post( ...//http variable is defined here setTimeout(function(){ that.http.post(... //http is not defined here } } |
2)使用箭头功能
1 2 3 4 5 | this.http.post( ...//http variable is defined here setTimeout(() => { that.http.post(... //http is not defined here } } |
第一种方法是旧的ES5,您不需要任何编译器,对于ES6版本(2),您需要使用类似Babel的东西。
有关arrow函数的更多信息,请访问:https://babeljs.io/docs/learn-es2015/