2012-11-17 57 views
1

看来我不能在setInerval函数里面使用this。这是为什么?什么是优雅的解决方案?在setInterval里面不能使用'this'

<html> 
<script> 
var something = function(tMessage){ 
    this.message = tMessage; 
}; 

something.prototype = { 
    start : function(counter){ 
     document.getElementById('result').innerHTML += this.message + "+++<br />"; 
     var looper = setInterval(
      function(){ 
       // This is printing "undefined" 
       document.getElementById('result').innerHTML += this.message + "<br />"; 
       if(!counter--) 
        clearInterval(looper); 
      }, 
      20 
     ); 
    } 
}; 


window.onload = function(){ 
    var e = new something("hi"); 
    e.start(2); 
} 
</script> 
<body> 
<div id="result"></div> 
</body> 
</html> 

编辑

感谢您的答案!但任何人都可以解释发送参数和设置和额外变量之间的区别吗?任何内存问题?

+1

因为这个==窗口里面的setInterval()回调函数 –

回答

5

这里的问题是,当你的函数被调用this指的是全局对象。为了保持当前的范围,你可以做一个封闭:

var looper = setInterval(
     (function(scope){ 
      return function(){ 
       // This will no longer be printing "undefined" 
       document.getElementById('result').innerHTML += scope.message + "<br />"; 
       if(!counter--) 
        clearInterval(looper); 
      }; 
     })(this), 
     20 
    ); 

相反handwaving,并试图解释倒闭(这我仍然在充分掌握过程),我将引导您到这个优秀的答案:https://stackoverflow.com/a/111200/1726343

1

因为您处于新的功能块中,所以不能使用this。我一直在创造一个局部变量(我敢肯定有一个更好的方法):

var c = this; 
setInterval(function(
    c.variable = 1; 
), 100); 
+0

虽然答案是正确的,但我不会说(不要混淆)你不能使用'this'。你可以但它指的是不同的上下文。 –

+0

是的,对,我只是想保持简单。 – tobspr

+0

我的理解正确。我接受Asads回答的唯一原因是,在参数情况下,“额外变量”的范围更小(可能出现的错误更少)。虽然我认为这个更具可读性。感谢您的回答:) –

0

添加

var self = this; 

只是你的电话给setInterval之前并使用自己的,而不是这个成组*间隔定义的函数

1

因为问题被标记为[prototypejs],但没有人回答使用Prototype,我决定写一个真正使用Prototype的答案(jsfiddle)。

var Something = Class.create({ 
    initialize: function(tMessage) { 
     this.message = tMessage; 
    }, 

    start: function(counter) { 
     this.counter = counter; 
     $("result").innerHTML += this.message + "+++<br />"; 
     this.looper = setInterval(this.addMessage.bind(this), 20); 
    }, 

    addMessage: function() { 
     $("result").innerHTML += this.message + "<br />"; 
     if (!this.counter--) { 
      clearInterval(this.looper); 
     } 
    } 
}); 

document.observe("dom:loaded", function() { 
    var e = new Something("hi"); 
    e.start(2); 
}); 
  1. 使用Class.create(),使更多的优雅类。
  2. 使用$()而不是document.getElementById()
  3. 使用document.observe("dom:loaded"),而不是window.onload
  4. 使用bind(this)绑定功能方面。

问题的关键在于函数的执行上下文中。无论你在哪里使用this,它只是指向当前的执行上下文。当您调用someObject.someFunction()时,someFunction()someObject的上下文中执行,并且this内部的someFunction()将指向someObject

但是你可以让作业someOtherObject.someFunction = someObject.someFunction,然后在someOtherObject.someFunction()this将指向someOtherObject。你

也可以通过参照功能到另一个功能,只要在setInterval()做,然后执行上下文将由setInterval()被定义(实际上这将是全球范围内,即this===window)。

为了将执行上下文绑定到该函数(预定义上下文,覆盖调用者的上下文),您需要使用.bind()方法。它返回一个新的函数,它会根据你想要的上下文调用你的原始函数,而不管在运行时哪个上下文。

+0

感谢您的链接。 :) +1 –

+0

我重申了这个问题,因为我不知道有一个名为'prototypejs'的库。 –