2013-09-25 79 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