2013-09-25 4 views
13

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

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

ответ

20

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

Fiddle

Другим способом вы можете сделать, это связать контекст, используя 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

Смежные вопросы