Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive call within prototype function

Alright so I have this prototyped object Stage, and every part of it works except for this recursive call.

Stage.prototype.start = function(key) {
        //var maxScrollLeft = document.getElementById("content").scrollWidth;
        $content.scrollLeft($content.scrollLeft() + this.initspeed);
        if(key < this.maxScrollLeft || key > 0) {
                setTimeout(function() {
                        this.start(key+2);
                },1); 
        }else{
                console.log("stop");
        }   
}   

Im trying to make it so that the Stage.prototype.start is called within this if statement, using this.start(); however I always get Uncaught TypeError: Object [object global] has no method 'start' I think it has to do with the call being in an anonymous function, any ideas on how I can fix this?

like image 756
Jake Schievink Avatar asked Sep 25 '13 01:09

Jake Schievink


1 Answers

this inside of your anonymous callback of setTimeout points to the global object, because the function is not bound to anywhere, so it gets hoisted to the global scope. In this case your callback is executed from window (browser) or global (node, etc.) context so this points to the global scope, since the function is called from that context. There are many ways to approach this issue. One simple way is to cache this to a variable and use it in the callback function.

 Stage.prototype.start = function(key) {
           var self = this; //cache this here
            //var maxScrollLeft = document.getElementById("content").scrollWidth;
            $content.scrollLeft($content.scrollLeft() + this.initspeed);
            if(key < this.maxScrollLeft || key > 0) {
                    setTimeout(function() {
                            self.start(key+2); //use it to make the call
                    },1); 
            }else{
                    console.log("stop");
            }   
    }   

Fiddle

Another way you can do is to bind a context using function.prototype.bind.

 Stage.prototype.start = function(key) {
            //var maxScrollLeft = document.getElementById("content").scrollWidth;
            $content.scrollLeft($content.scrollLeft() + this.initspeed);
            if(key < this.maxScrollLeft || key > 0) {
                    setTimeout((function() {
                            this.start(key+2); //now you get this as your object of type stage
                    }).bind(this),1);  //bind this here
            }else{
                    console.log("stop");
            }   
    }   

Fiddle

like image 187
PSL Avatar answered Nov 14 '22 19:11

PSL