Javascript setInterval 和 `this` 解决方案
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2749244/
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
Javascript setInterval and `this` solution
提问by Pablo
I need to access thisfrom my setIntervalhandler
我需要this从我的setInterval处理程序访问
prefs: null,
startup : function()
{
// init prefs
...
this.retrieve_rate();
this.intervalID = setInterval(this.retrieve_rate, this.INTERVAL);
},
retrieve_rate : function()
{
var ajax = null;
ajax = new XMLHttpRequest();
ajax.open('GET', 'http://xyz.com', true);
ajax.onload = function()
{
// access prefs here
}
}
How can I access this.prefs in ajax.onload?
如何访问 this.prefs ajax.onload?
回答by AnthonyWJones
The setInterval line should look like this:-
setInterval 行应如下所示:-
this.intervalID = setInterval(
(function(self) { //Self-executing func which takes 'this' as self
return function() { //Return a function in the context of 'self'
self.retrieve_rate(); //Thing you wanted to run as non-window 'this'
}
})(this),
this.INTERVAL //normal interval, 'this' scope not impacted here.
);
Edit: The same principle applies to the " onload". In this case its common for the "outer" code to do little, it just sets up the request an then sends it. In this case the extra overhead an additinal function as in the above code is unnecessary. Your retrieve_rate should look more like this:-
编辑:同样的原则适用于“ onload”。在这种情况下,“外部”代码通常做的很少,它只是设置请求然后发送它。在这种情况下,上述代码中的附加函数的额外开销是不必要的。您的retrieve_rate 应该更像这样:-
retrieve_rate : function()
{
var self = this;
var ajax = new XMLHttpRequest();
ajax.open('GET', 'http://xyz.com', true);
ajax.onreadystatechanged= function()
{
if (ajax.readyState == 4 && ajax.status == 200)
{
// prefs available as self.prefs
}
}
ajax.send(null);
}
回答by Nechehin
this.intervalID = setInterval(this.retrieve_rate.bind(this), this.INTERVAL);
回答by Joel Fillmore
The default behavior of setIntervalis to bind to the global context. You can call a member function by saving a copy of the current context. Inside retrieve_rate the thisvariable will be correctly bound to the original context. Here is what your code would look like:
的默认行为setInterval是绑定到全局上下文。您可以通过保存当前上下文的副本来调用成员函数。在retrieve_rate 中,this变量将正确绑定到原始上下文。您的代码如下所示:
var self = this;
this.intervalID = setInterval(
function() { self.retrieve_rate(); },
this.INTERVAL);
Bonus tip: For a plain function reference (as opposed to an object reference which has a member function) you can change the context by using JavaScript's callor applymethods.
额外提示:对于普通函数引用(与具有成员函数的对象引用相对),您可以使用 JavaScriptcall或apply方法更改上下文。
回答by Martlark
With improving browser support the time is now good to use the EcmaScript 6 enhancement, the arrow =>method, to preserve thisproperly.
随着浏览器支持的改进,=>现在是时候使用EcmaScript 6 增强、箭头方法来this正确保存了。
startup : function()
{
// init prefs
...
this.retrieve_rate();
this.intervalID = setInterval( () => this.retrieve_rate(), this.INTERVAL);
},
Using => method preserves the thiswhen retrieve_rate()is called by the interval. No need for funky self or passing thisin parameters
使用=>方法保留this时retrieve_rate()由间隔调用。不需要时髦的自我或传入this参数
回答by Daniel Apostolov
window.setInterval(function(){console.log(this)}.bind(this), 100)
window.setInterval(function(){console.log(this)}.bind(this), 100)
this is legal in javascript and saves lots of code :)
这在 javascript 中是合法的,并且可以节省大量代码 :)
回答by Dbl
This would be the cleanest solution, since most of the time you actually want to switch the this context for your consecutive method calls:
这将是最干净的解决方案,因为大多数时候您实际上希望为连续的方法调用切换 this 上下文:
Also it's easier to grasp the concept of.
也更容易掌握概念。
// store scope reference for our delegating method
var that = this;
setInterval(function() {
// this would be changed here because of method scope,
// but we still have a reference to that
OURMETHODNAME.call(that);
}, 200);
回答by gaetanoM
With modern browsers the setInterval method allows additional parameters which are passed through to the function specified by func once the timer expires.
在现代浏览器中, setInterval 方法允许附加参数,一旦计时器到期,这些参数就会传递给 func 指定的函数。
var intervalID = scope.setInterval(func, delay[, param1, param2, ...]);
var intervalID = scope.setInterval(func, delay[, param1, param2, ...]);
Hence, a possible solution can be:
因此,一个可能的解决方案可以是:
this.intervalID = setInterval(function (self) {
self.retrieve_rate();
}, this.INTERVAL, this);
A demo:
一个演示:
var timerId;
document.querySelector('#clickMe').addEventListener('click', function(e) {
timerId = setInterval(function (self) {
self.textContent = self.textContent.slice(0, -1);
if (self.textContent.length == 0) {
clearInterval(timerId);
self.textContent = 'end..';
}
}, 250, this);
})
<button id="clickMe">ClickMe</button>
回答by Matthew Flaschen
prefs: null,
startup : function()
{
// init prefs
...
this.retrieve_rate();
var context = this;
this.intervalID = setInterval(function()
{
context.retrieve_rate();
}, this.INTERVAL);
},
retrieve_rate : function()
{
var ajax = null;
ajax = new XMLHttpRequest();
ajax.open('GET', 'http://xyz.com', true);
var context = this;
ajax.onload = function()
{
// access prefs using context.
// e.g. context.prefs
}
}
回答by Crozin
That's not a beauty solution but it's in common usage:
这不是美容解决方案,但它很常见:
var self = this;
var ajax = null;
//...
ajax.onload = function() {
self.prefs....;
}

