Рекурсивный вызов в функции прототипа

Хорошо, поэтому у меня есть этот прототипированный объект Stage, и каждая его часть работает, за исключением этого рекурсивного вызова.

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

Я пытаюсь сделать так, чтобы Stage.prototype.start вызывается внутри этого оператора if, используя this.start(); но я всегда получаю Uncaught TypeError: Object [object global] has no method 'start' Я думаю, что это связано с вызовом, находящимся в анонимной функции, любыми идеями о том, как я могу это исправить?

Ответ 1

this внутри вашего анонимного обратного вызова setTimeout указывает на глобальный объект, потому что функция не привязана нигде, поэтому она поднимается в глобальную область. В этом случае ваш обратный вызов выполняется из window (браузера) или global (узла и т.д.) Контекста, поэтому this указывает на глобальную область действия, поскольку функция вызывается из этого контекста. Есть много способов подойти к этой проблеме. Один простой способ - кэшировать this переменную и использовать ее в функции обратного вызова.

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

скрипка

Другой способ, который вы можете сделать, - связать контекст с помощью функции.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");
            }   
    }   

скрипка