2013-09-25 80 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"); 
     } 
} 

我試着讓這個在Stage.prototype.start的if語句稱爲內這一點,使用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