递归超时会失去对自身的可见性

时间:2013-11-25 06:31:21

标签: javascript recursion

我定义了一个API对象:

function API() {
  var self = this;
  return {
    getRandomArticle: function() {
      $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=50000&format=json&callback=?", function (data) {
        for(var id in data.query.pages) {
          console.log(data.query.pages[id].extract);
        }
      });
    },
    repeatAPICall: function() {
      self.getRandomArticle();
      console.log(self);
      setTimeout(self.repeatAPICall, 5000);
    }
  }
}

然后我使用window.test = new API();实例化了API对象。 当我转到Chrome开发工具并致电window.test.repeatAPICall()时,它会运行一次,然后失败并说TypeError: Object #<API> has no method 'getRandomArticle'

我怀疑递归调用的行为方式与我的预期不同,我做错了什么?

工作代码:

function API() {
  var self = this;
    self.getRandomArticle = function() {
      $.getJSON("http://en.wikipedia.org/w/api.php?action=query&generator=random&grnnamespace=0&prop=extracts&exchars=50000&format=json&callback=?", function (data) {
        for(var id in data.query.pages) {
          console.log(data.query.pages[id].extract);
        }
      });
    },
    self.repeatAPICall = function() {
      self.getRandomArticle();
      console.log(self);
      setTimeout(self.repeatAPICall, 5000);
    }
    return this;
}
window.test = new API();

2 个答案:

答案 0 :(得分:1)

现在你已经修复了“自我”与“这个”,下一个更改是使用

self.getRandomArticle= ...
self.repeatAPICall=...

然后只返回self / this。这应该工作。现在,你有两个对象 - 这个和你返回的对象。

答案 1 :(得分:0)

您的主要问题是将this.repeatAPICall传递给setTimeout。在JavaScript中调用方法时,this关键字指向调用它的对象:

var something = {
    foo : function(){
        return this;
    }
};

something.foo();    //=> something

但是,如果将函数分配给另一个变量,则上下文会更改(到全局window对象):

var something = {
    foo : function(){
        return this;
    }
};

something.foo();    //=> something
var bar = something.foo;
bar();              //=> window

这就是上面发生的事情;你将函数的引用传递给setTimeout,然后失去了正确的上下文。

相反,你需要传入一个保持上下文的函数;您可以使用self = this语句,如下所示:

repeatAPICall: function() {
  self = this;
  self.getRandomArticle();
  setTimeout(function(){
    self.repeatAPICall();
    }, 5000);

这会创建一个匿名函数,它会记住self对象的状态(这就是JavaScript变量作用域的工作原理)。当调用该函数时,它可以调用repeatAPICall作为该对象的方法,而不是作为没有上下文的函数。

接受的答案避免了必须这样做(每种方法都可以访问self),但希望这可以解释为什么它不起作用。