mfujica February 2016

"this" within setTimeout self executing function is undefined

I know that this within setTimeout will correspond by default to window, so I have been using bind and passing it through to the self executing function, but when setTimeout finally runs (it's fine on the first run, called by TeaBot._manageTeaRound(), but it's not fine when self executing) this is undefined. Here's my code, where am I going wrong? (I have deleted some lines of code which might not be relevant). Thanks for your help :)

TeaBot.prototype._manageTeaRound = function(originalMessage, channel){
    var self = this;
    self.teaMaker = this._getUserById(originalMessage.user);

    //now wait 3 minutes for people to send their order
    self._runTimer(self,channel);
}
TeaBot.prototype._runTimer =function(self, channel) {
    // do stuff
    console.log(self.teaMaker.name); //undefined

    var interval = self.interval,
        teaMaker = self.teaMaker;

    console.log("self.interval is " + self.interval);

    if(interval === 0){

        interval++;
        self.interval = interval;

        setTimeout(self._runTimer.bind(self, channel), 180000);

    }else{
        self.interval = 0;
    }
}

Answers


Rocket Hazmat February 2016

This is because you are not using the value of this inside of _runTimer. You are binding a value this, but _runTimer couldn't care less.

_runTimer cares about its two parameters. The 1st being the context (self). The way your code is structured, there's no reason to use .bind here.

setTimeout(function(){
    self._runTimer(self, channel);
}, 180000);

(Since you are passing the context (self) to the function, it makes no sense to have _runTimer be a part of TeaBot.prototype, since it needs a context passed to it.)


As an alternative, you can drop the self parameter, and have _runTimer reference this. That's when you would need to use .bind().

TeaBot.prototype._manageTeaRound = function(originalMessage, channel){
    this.teaMaker = this._getUserById(originalMessage.user);

    //now wait 3 minutes for people to send their order
    this._runTimer(channel);
};
TeaBot.prototype._runTimer = function(channel) {
    // do stuff
    console.log(this.teaMaker.name);

    var interval = this.interval,
        teaMaker = this.teaMaker;

    console.log("this.interval is " + this.interval);

    if(interval === 0){

        interval++;
        this.interval = interval;

        setTimeout(this._runTimer.bind(this, channel), 180000);

    } else{
        this.interval = 0;
    }
};


Radosław M February 2016

This line is problematic:

setTimeout(self._runTimer.bind(self, channel), 180000);

Function TeaBot.prototype._runTimer expects self to be the first param - Function.prototype.bind() first param is context (function's this). Try use it like this:

setTimeout(self._runTimer.bind(self, self, channel), 180000);

Or leave context empty, becouse you are not using this at all:

setTimeout(self._runTimer.bind(undefined, self, channel), 180000);

Post Status

Asked in February 2016
Viewed 1,761 times
Voted 10
Answered 2 times

Search




Leave an answer