可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to use setTimeout()
inside a class function in JavaScript. The setTimeout()
is supposed to trigger another method in the same Class, so the function I am passing it is written as window.setTimeout("this.anotherMethod", 4000)
. That bring the problem: this
references the calling Object, in the case of setTimeout()
it is window
. How can I use enclosures to return a reference to the Class Object itself?
myObject = function(){
this.move = function(){
alert(this + " is running");
}
this.turn = function(){
alert(this + " is turning");
}
this.wait = function(){
window.setTimeout("this.run" ,(1000 * randomNumber(1,5)));
}
this.run = function(){
switch(randomNumber(0,2)){
case 0:
this.move();
break;
case 1:
this.turn();
break;
case 2:
this.wait();
}
}
}
回答1:
You can do this:
var that = this;
setTimeout(function () {
that.doStuff();
}, 4000);
You can also bind
for more succinct code (as originally pointed out by @Raynos):
setTimeout(this.doStuff.bind(this), 4000);
bind
is a standard library function for exactly this coding pattern (ie capturing this
lexically).
回答2:
You can also bind a function to scope.
setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));
Be warned Function.prototype.bind
is ES5
回答3:
this
can be problematic in javascript, as you've discovered.
I usually work around this by aliasing this
inside the object so that I can use the alias whenever I need a reference back to the containing object.
MyObject = function ()
{
var self = this;
// The rest of the code goes here
self.wait = function(){
window.setTimeout(self.run ,(1000 * randomNumber(1,5)));
}
}
回答4:
this.wait = function(){
var self = this;
window.setTimeout(function() { self.run() } ,(1000 * randomNumber(1,5)));
}
So you store the reference to the object you're calling .run on in a local variable ('self').
回答5:
this
is sensitive to the context in which it is called. When you pass a string to setTimeout
then that is eval
ed in a completely different context.
You need to preserve the current value of this
(by copying it to a different variable) and maintain the scope (by not using (implied) eval
).
this.wait = function(){
var self = this;
setTimeout(function () { self.run() },
(1000 * randomNumber(1,5))
);
}
回答6:
At the top of your main myObject
make a new reference to the current value of this
:
var self = this;
and then create a closure for your timer callback that uses that new reference instead of the global object that setTimeout
will use as the default context in callbacks:
setTimeout(function() {
self.run();
}, 4000);
回答7:
var timeoutID = window.setTimeout(func, delay, [param1, param2, ...]);
inside func
, this
always refer to the global object. you can pass in the current object into func,
var timeoutID = window.setTimeout(func, delay, this);
function func(that) {...}
unfortunately it does NOT work in IE
Note that passing additional parameters to the function in the first syntax does not work in Internet Explorer.
回答8:
Have you tried;
window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));
回答9:
you can just use the arrow function syntax:
setTimeout(() => {
this.doStuff();
}, 4000);
回答10:
You can use this code instead, which works in all modern browsers -
setTimeout(function(thisObj) {thisObj.run();},1000,this);
Ref: http://klevo.sk/javascript/javascripts-settimeout-and-how-to-use-it-with-your-methods/
回答11:
Shorter way. Without anonymous func.
var self = this;
setTimeout(self.method, 1000);
回答12:
It is not recommended to use setTimeout or setInterval using strings
setTimeout("myFunction()", 5000);
//this is the same as
setTimeout(function(){ eval("myFunction()"); }, 5000)); //<-- eval == BAD
回答13:
Ran into a more complex situation...class A has a member of type B and a method that calls setTimeout which calls a method on class B. Solved as follows:
class A {
constructor(b) {
this.b = b;
}
setTimer(interval) {
setTimeout(this.b.tick.bind(this.b), interval);
}
}
class B {
constructor(name){
this.name = name;
this.ele = window.document.getElementById('B');
}
tick() {
console.log(this);
this.ele.innerText += ' ' + this.name;
}
}
Which bound A.b to this within B.tick and worked.
Here's a fiddle with bind
: https://jsfiddle.net/jrme9hyh/
And one without bind
which fails: https://jsfiddle.net/2jde8tq3/