2012-11-17 55 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'的庫。 –