Javascript setTimeout 内部的变量表示未定义,但在外部时已定义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36209784/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Variable inside setTimeout says it is undefined, but when outside it is defined
提问by user2924127
I have a class. I need to do some http work inside of a timeout. The problem I am faceing is the http variable inside the timeout keeps saying it is undefined.
我有一堂课。我需要在超时内做一些 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
}
}
}
回答by thecardkid
The reason for this is that the callback function inside setTimeout is in a different lexical environment. This is why in ES6+ functions can be defined using =>
. This is so that the code within a function shares the same scope as the function.
这样做的原因是 setTimeout 中的回调函数处于不同的词法环境中。这就是为什么在 ES6+ 中可以使用=>
. 这是为了使函数内的代码与函数共享相同的作用域。
To fix this, you can either use ES6+ syntax, where instead of function(a,b,args) {...}
you would use (a,b,args) => {...}
:
要解决此问题,您可以使用 ES6+ 语法,而不是function(a,b,args) {...}
使用(a,b,args) => {...}
:
setTimeout( () => {
this.http.post(...)
});
or with ES5 syntax:
或使用 ES5 语法:
var root = this;
setTimeout(function(){
root.http.post(...)
}
Hope this helps!
希望这可以帮助!
回答by Jesse Lee
In JavaScript the this
keyword is used to access the context
in which a function is invoked. Functions in JavaScript are always invoked with a context whether you invoke them using the .methodName()
syntax or without it, unless the 'use strict'
flag is set in the current scope.
在 JavaScript 中,this
关键字用于访问context
调用函数的位置。JavaScript 中的函数总是使用上下文调用,无论您使用.methodName()
语法还是不使用语法调用它们,除非'use strict'
在当前作用域中设置了标志。
When a function is invoked without a context like this:
当一个函数在没有上下文的情况下被调用时:
myFunction()
the context is assumed by the runtime to be the global window object (unless the 'use strict'
flag is set, in which case the context will be undefined.)
运行时假定上下文是全局窗口对象(除非'use strict'
设置了标志,在这种情况下上下文将是未定义的。)
Note: When using ES6 with a transpiler like Babel, strict mode is set by default in the output.
注意:当使用 ES6 和 Babel 等转译器时,默认情况下在输出中设置严格模式。
When a reference to a function is saved on an object, you can invoke that function with the object as the context of 'this' using the dot syntax.
当对函数的引用保存在对象上时,您可以使用点语法将该对象作为“this”的上下文来调用该函数。
var myObj = {
myFunc: function(){}
};
// myFunc invoked like this, the value of 'this' inside myFunc will be myObj.
myObj.myFunc();
Manipulate 'this':
操纵“这个”:
Call and Apply
打电话申请
You can always change the context of a function by invoking it with the .call or .apply methods. In this case you have an anonymous function which is not invoked by you, but rather is invoked by the setTimeout function. Because of that, you won't be able to take advantage of .call or .apply.
您始终可以通过使用 .call 或 .apply 方法调用函数来更改函数的上下文。在这种情况下,您有一个匿名函数,它不是由您调用,而是由 setTimeout 函数调用。因此,您将无法利用 .call 或 .apply。
Bind
绑定
Instead, you can create a new function that has a custom context by using the .bind method. By invoking .bind() on your anonymous function, an new function will be returned which has your custom context bound to 'this'. That way you can pass your custom bound function as data to setTimeout.
相反,您可以使用 .bind 方法创建一个具有自定义上下文的新函数。通过在您的匿名函数上调用 .bind(),将返回一个新函数,该函数将您的自定义上下文绑定到“this”。这样您就可以将自定义绑定函数作为数据传递给 setTimeout。
setTimeout(function(){
// your code.
}.bind(this), 1000);
now inside the anonymous function the 'this' keyword would be bound to the correct value.
现在在匿名函数中,'this' 关键字将绑定到正确的值。
Lexical 'this':
词法“这个”:
In ES6 however, when using an arrow functionthe rules about 'this' change. If you use this syntax you will see the context of 'this' will stay the same as whatever it is in the current scope.
然而,在 ES6 中,当使用箭头函数时,关于“this”的规则发生了变化。如果您使用此语法,您将看到“this”的上下文将与当前范围内的任何内容保持相同。
setTimeout(() => {
// Hey I can access 'this' in here!
}, 1000);
Saving a reference:
保存参考:
If you look at the compiled output from Babel you will see Babel keeps track of the context by saving references to 'this' with _this1, _this2 and so forth.
如果您查看 Babel 的编译输出,您将看到 Babel 通过使用 _this1、_this2 等保存对“this”的引用来跟踪上下文。
To use this method yourself simply declare a new variable ( it's common to use 'that' or 'self' ) and access the value using it inside your anonymous function like so:
要自己使用此方法,只需声明一个新变量(通常使用 'that' 或 'self' )并在匿名函数中使用它访问该值,如下所示:
var self = this;
setTimeout(function(){
self.http.post...
});
Hope this helps.
希望这可以帮助。
For more explanation developer.mozilla.org has a good article describing the behavior of 'this' inside a functions scope.
更多解释 developer.mozilla.org 有一篇很好的文章描述了“this”在函数作用域内的行为。
回答by Pankaj Parkar
You should use arrow function here, to preserve existense of this.
你应该在这里使用箭头函数,以保留它的存在。
setTimeout(()=>{
this.http.post(... //http is not defined here
})
In doing so, this
inside of the function is bound to the outer context. It is the same as:
这样做时,this
函数内部绑定到外部上下文。它与以下内容相同:
setTimeout(function(){
this.http.post();
}.bind(this));
回答by Lukas Liesis
it's not same this
inside setTimeout
when you use function(){...
当您使用时,this
内部不一样setTimeout
function(){...
2 most popular ways for this issue:
解决此问题的 2 种最流行方法:
1) use extra variable to store outside "this"
1)使用额外的变量存储在“this”之外
var that = this;
this.http.post( ...//http variable is defined here
setTimeout(function(){
that.http.post(... //http is not defined here
}
}
2) use arrow functions
2)使用箭头函数
this.http.post( ...//http variable is defined here
setTimeout(() => {
that.http.post(... //http is not defined here
}
}
1st way is old ES5 and you don't need any compilers, for ES6 version (#2) you will need to use something like babel.
第一种方式是旧的 ES5,您不需要任何编译器,对于 ES6 版本(#2),您将需要使用类似 babel 的东西。
find more about arrow functions & babel here: https://babeljs.io/docs/learn-es2015/
在此处找到有关箭头函数和 babel 的更多信息:https: //babeljs.io/docs/learn-es2015/