【问题标题】:Custom Object calling Methods with setTimeout loses scope带有 setTimeout 的自定义对象调用方法失去作用域
【发布时间】:2011-01-21 01:25:58
【问题描述】:

我在构建 Javascript 对象以及使用 setTimeout 在该对象中调用方法时遇到问题。我尝试了各种解决方法,但总是在循环的第二部分中,范围成为窗口对象而不是我的自定义对象。警告:我是 javascript 的新手。

我的代码:

$(function() {
 slide1 = Object.create(slideItem);
 slide1.setDivs($('#SpotSlideArea'));
 slide1.loc = 'getSpot';
 slide2 = Object.create(slideItem);
 slide2.setDivs($('#ProgSlideArea'));
 slide2.loc = 'getProg';
 slide2.slide = 1;
 setTimeout('triggerSlide(slide1)', slide1.wait);
 setTimeout('triggerSlide(slide2)', slide2.wait);
});

function triggerSlide(slideObject) {
 slideObject.changeSlide(slideObject);
}

var slideItem = {
 div1: null,
 div2: null,
 slide: 0,
 wait: 15000,
 time: 1500,
 loc: null,
 changeSlide: function(self) {
  this.slide ? curDiv = this.div1:curDiv = this.div2;
  $(curDiv).load(location.pathname + "/" + this.loc, this.slideGo(self));
 },
 setDivs: function(div) {
  var subDivs = $(div).children();
  this.div1 = subDivs[0];
  this.div2 = subDivs[1];
 },
 slideGo: function(self) {
  if(this.slide) {
   $(this.div2).animate({
    marginLeft: "-300px"
   }, this.time);
   $(this.div1).animate({
    marginLeft: "0"
   }, this.time);
   setTimeout('triggerSlide(self)', this.wait);
  } else {    
   $(this.div1).animate({
    marginLeft: "300px"
   }, this.time);
   $(this.div2).animate({
    marginLeft: "0"
   }, this.time);
   setTimeout('triggerSlide(self)', this.wait);
  }   
  this.slide ? this.slide=0:this.slide=1;
 }
}

我最近的尝试是构建辅助函数 triggerSlide 以便我可以尝试通过我的方法传递对对象的引用,但即使这样似乎也不起作用。

我可以使用 setInterval 并且它可以工作,但是:

  1. 我想确保动画在计时器重新启动之前完成
  2. 我不知道如何以这种方式解决问题。 :)

【问题讨论】:

    标签: javascript oop scope settimeout


    【解决方案1】:

    我现在无法测试这段代码,但这有帮助吗?

    setTimeout(function(){triggerSlide(slide1)}, slide1.wait);
    

    【讨论】:

    • UGG。为什么要将它作为字符串传递?
    • 相对于什么?指定函数名?
    • 是的,指定函数名或匿名函数。在您的示例中,完全去掉引号就可以了。然而,无论如何,他的机制是不必要的复杂,它真的应该做不同的。
    • 啊,对。匿名函数是我的意图。该字符串是我的语法无知。我会纠正它。希望你的回答对他更有帮助。
    • 酷。走着瞧; Javascript 是一种奇怪的入门语言——它既容易又难。
    【解决方案2】:

    这是 jQuery,对吗? animate()有一个回调参数;在动画完成后将您想要调用的函数传递给它,jQuery 将负责调用它。回调应该可以很好地捕获您想要的范围。

    【讨论】:

      【解决方案3】:

      对于开始使用该语言(以及 Stackoverflow)的 Javascript 程序员来说,这应该是必读的。

      与 Java 不同,函数没有内在的“绑定”到任何对象,无论它们是如何声明的。对象上下文的绑定只发生在函数调用时。因此,当您将对函数的引用传递给“setTimeout”之类的东西时,您从某个对象中获取该函数并不重要。它只是一个函数,“setTimeout”将使用默认上下文(window 对象)调用它。

      有很多方法可以解决这个问题(我不会称其为“问题”;这是语言的事实,而且非常强大)。如果你使用某种框架会更容易。

      另一件事:您将超时和间隔处理程序绑定为包含代码的字符串。这是一种非常丑陋的做法,因此您应该习惯于形成函数表达式——即,其值为函数的表达式。

      例如,对于您的“slideItem”处理程序,您可以这样做:

      // ...
      setTimeout(function() { slideItem.changeSlide(); }, 5000);
      

      这样,超时机制调用的函数将始终以您的“slideItem”对象作为上下文调用“changeSlide”。您不需要“changeSlide”中的“self”参数,因为“this”将指向正确的对象。

      [edit] 我注意到您实际上在使用 jQuery,这是一件好事。

      【讨论】:

      • +1 字符串中的代码通常最好避免,除非绝对必要。这包括new Function('some code');setTimeout("doSomething()", 0); 和大家最喜欢的eval('some code');。前两个我从未看到有必要,第三个仅用于 JSON 和输入数学表达式:-)
      • 我尝试了上述方法,它适用于初始调用,但重复操作的调用(slideGo() 中的 setTimeout() 调用仍然不起作用。我将它们格式化为上述,但利用它代替上面的slideItem。即setTimeout(function() {this.changeSlide();},this.wait);我在Firebug中收到一个错误,this.changeSlide()不是一个函数。我很早就知道'this' 引用我的 slideItem 的 slideGo 方法,但是当第二个 setTimeout 调用发生时它似乎没有出现。这就是我感到困惑的地方。
      • 我还应该提到,我尝试在我的 slideGo 方法的开头添加 that=this,但是这似乎是在全局范围内添加的,而不仅仅是在方法内。我在页面上有多个对象,因此只有其中一个具有动画效果,由每个 setTimeout 触发。
      • 好吧,如果它不起作用,那只是意味着您没有在对“setTimeout”的调用中正确设置。他们都应该使用类似于我上面描述的匿名函数设置的东西(假设“slideItem”是您实际想要使用的上下文对象;我很难说出发生了什么。)
      • 啊啊啊啊!!在我对权力和荣耀的疯狂竞赛中,我显然错过了一些重要的事情(我现在知道了)。 JS 显然处理 "that = this" 与 "var that = this" 不同。第二个工作完美。所以我在 slideGo 中的代码现在是 setTimeout(function() { that.changeSlide(); }, this.wait);这意味着我可能可以减少方法的数量,并将 slideGo 中的代码移回 changeSlide 以简化一些事情(我最初就是这样,但一直在尝试解决这个问题)。感谢 Pointy 的出色解释。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 1970-01-01
      • 2015-11-23
      • 1970-01-01
      相关资源
      最近更新 更多