2009-07-24 34 views
1

我是新來的閉包,並有一個'讓我通過做大多數事情'的理解的JavaScript,所以我想知道如何改善等等,這是我試圖有一個對象中有一個計數器......試圖改進/進一步理解。Javascript setTimout對象/函數幫助

編輯:下面的代碼工作,當然...但可能它是錯誤的(是嗎?)...我甚至沒有接近它是代碼是否正確或不正確的想法..我在哪裏可以改進...有沒有更好的方法來在對象/函數中使用計時器?

function myObj() { 
    this.outputId = 'div_output1'; 
    this.counter = 0; 
    this.limit = 10; 
    this.count = function() { 
     // reference to self 
     var me = this; 

     if (me.doStuff(me)) setTimeout(function() { 
      me.count(); 
     },1000); 
    }; 
    this.doStuff = function(me) { 
     if (me.counter >= me.limit) { 
      document.getElementById(me.outputId).innerText = 'count reached limit'; 
      return false; 

     } else { 
      document.getElementById(me.outputId).innerText = 'count = ' + me.counter; 
      me.counter += 1; 
      return true; 
     } 
    } 
} 

對象//例如使用...

window.onload = function() { 

    var x = new myObj; 
    x.outputId = 'div_output2'; 
    x.count(); 

    var y = new myObj; 
    y.limit = 8; 
    y.count(); 
} 
+0

到底是用代碼去什麼錯你貼? – Triptych 2009-07-24 03:29:27

+0

我不認爲任何事情可能會發生錯誤...但聽說內存泄漏和掌握概念的一般複雜性...我相信有可能有更好的方法,更正確的方法... – davidsleeps 2009-07-24 03:31:44

+0

Can你在問題中添加了什麼問題? – Alex 2009-07-24 03:34:44

回答

2

您正在正確使用閉包。因爲當setTimeout調用你的函數時,'this'將會是'Window'對象,你必須創建一個閉包(通過給我分配'this'來完成)並訪問它。

無論如何,我仍然會寫你的代碼有點不同。我會讓doStuff調用本身,而不是使其返回true/false,然後決定是否再次調用doStuff。

我不喜歡你如何將'this'對象傳遞給this.doStuff函數。這是沒有必要的。要了解'this'如何在JavaScript中運行,請選中my detailed answer on the subject

function Counter(opts) 
{ 
    this.outputId = opts.outputId || 'div_output1'; 
    this._currentCount = 0; 
    this.limit = opts.limit || 10; 

    this.count = function() 
       {       
        this.deferDoStuff(); 
       }; 

    this.deferDoStuff = function() 
       { 
        var me = this; 
        setTimeout(function() { me.doStuff(); }, 1000); 
       }; 

    this.doStuff = function() 
        { 
         if(this._currentCount > this.limit) 
         { 
          document.getElementById(this.outputId).innerHTML = 'Count limit reached'; 
          return; 
         } 

         document.getElementById(this.outputId).innerHTML = 'count = ' + this._currentCount; 
         this._currentCount++; 
         this.deferDoStuff(); 
        }; 
} 

用法:

 var x = new Counter({ 'outputId' : 'div1' }); 
     var y = new Counter({ 'outputId' : 'div2' }); 

     x.count(); 
     y.count(); 
2

我會用封閉了this只是在回調函數的函數調用。像往常一樣,該對象的其他方法可以使用this。回調需要顯式引用該對象,因爲它需要從「外部」調用對象方法。但是對於被調用的方法,它只是一個普通的函數調用,它可以像往常一樣使用隱式的this來訪問它的對象。

我也正常運行的方法聲明瞭構造爲對象的原型,因爲它更清晰,更高效:

function myObj() { 
    this.outputId = 'div_output1'; 
    this.counter = 0; 
    this.limit = 10; 
} 

myObj.prototype.count = function() { 
    // reference to self 
    var me = this; 
    var callback = function() { 
     me.count(); 
    }; 

    if (this.doStuff()) 
     setTimeout(callback,1000); 
} 

myObj.prototype.doStuff = function() { 
    if (this.counter >= this.limit) { 
      document.getElementById(this.outputId).innerText = 'count reached limit'; 
      return false; 

    } else { 
      document.getElementById(this.outputId).innerText = 'count = ' + this.counter; 
      this.counter += 1; 
      return true; 
    } 
} 
0

一些我會清理代碼的方法是:

  1. 使用封裝即不要只公開所有變量&函數。你的doStuff方法在該對象上是public的,這意味着任何人都可以調用這個方法,而不僅僅是count方法。這也適用於count,limit和outputId。相反,他們應該傳遞給構造函數。

  2. 使引用對象「我」成爲類的私有成員,所以您不要在方法中設置它。如果您要使用調用或應用方法調用該方法,則可能會出現問題,因爲此方法的上下文已更改。

例如,

var obj = new myObj(); 
var otherobj = {}; 
obj.call.call(otherobj); 
  • 我也會改變內聯,如果你在計數有。你只是要求麻煩!如果(doStuff())setTimeout(function(){ me.count(); },1000);

  • 這裏是我的所有建議

    function myObj(outputId, limit) { 
        var counter = 0, 
         me = this; 
    
        function doStuff() { 
         if (counter >= limit) { 
           document.getElementById(outputId).innerText = 'count reached limit'; 
           return false; 
    
         } else { 
           document.getElementById(outputId).innerText = 'count = ' + counter; 
           counter += 1; 
           return true; 
         } 
        } 
        this.count = function() { 
         if (doStuff()) { 
          setTimeout(function() { 
           me.count(); 
          },1000); 
         } 
        }; 
    } 
    
    +0

    我想你想寫obj.count.call。另外,我不同意第二點。您可能並不總是希望修復對「this」的引用,因爲我可能想要在不同的對象上調用您的函數。檢查我的詳細發佈在此:http://stackoverflow.com/questions/1007340/javascript-function-aliasing-doesnt-seem-to-work/1162192#1162192 – SolutionYogi 2009-07-24 03:59:16

    +0

    因爲你使用的construur論點的限制,你有刪除限制屬性。這可能不是一個理想的解決方案。 – SolutionYogi 2009-07-24 04:00:44

    0

    我沒有看到任何實際問題的代碼,但是有幾件事我可能會清理。

    • 我會指定outputId和limit作爲構造函數的參數。如果你仍然想要默認值,你可以檢查未定義的參數,或傳遞一個選項對象。
    • doStuff中的參數me是多餘的,因爲它總是與this相同,並且您不需要在閉包中捕獲它。
    • 我可能會寫doStuff這樣的:

      var outputDiv = document.getElementById(this.outputId); 
      this.doStuff = function() { 
          this.counter++; 
          if (this.counter > this.limit) { 
           outputDiv.innerText = 'count reached limit'; 
           return false; 
          } 
          else { 
           outputDiv.innerText = 'count = ' + this.counter; 
           return true; 
          } 
      } 
      

      這是小調式的事情,但我認爲這是更加明顯,doStuff正在修改的計數器,因爲它是在函數的開始,而不是埋內else子句。而且,將getElementById移到該函數外部會稍微減少重複的代碼。