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

Recursive timeout loses visibility to itself

本文关键字:可见性 失去 超时 递归      更新时间:2023-09-26

我定义了一个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 Dev工具并调用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();

现在你已经修复了"self"与"this",下一个变化是使用

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

然后只是返回自我/这个。 这应该行得通。 现在,您有两个对象 - 这个和您返回的对象。

您的主要问题是将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(,但希望这可以解释为什么它不起作用。