开发者

setTimeout() inside JavaScript Class using "this"

I am trying to use setTimeout() inside a class function in JavaScript. The setTimeout() is supposed to trigger another method in the sa开发者_开发百科me 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();
    }
}

}


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).


You can also bind a function to scope.

setTimeout(this.run.bind(this) ,(1000 * randomNumber(1,5)));

Be warned Function.prototype.bind is ES5


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)));
    }
}


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').


class A{

   setTimeout(()=>{

       // here this != undefined because of arrow function

  },500);

}


this is sensitive to the context in which it is called. When you pass a string to setTimeout then that is evaled 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))
              );
}


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);


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.


you can just use the arrow function syntax:

setTimeout(() => {
     this.doStuff();
 }, 4000);


Have you tried;

window.setTimeout("myObject.run" ,(1000 * randomNumber(1,5)));


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/


Shorter way. Without anonymous func.

    var self = this;
    setTimeout(self.method, 1000);


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


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/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜