2012-01-27 73 views
0

現在已經很晚了,我的大腦中Douglas Crockford住的地方已經關閉了。我曾嘗試過幾件事,但沒有按照預期做。超時後javascript變量作用域/關閉循環

我有一個畫布,畫兩條線,然後淡出他們的計時器,但只有循環中的最後一行正在淡出。這裏是我的小提琴,看不起線50ish在JS,周圍看到它在行動拖動鼠標在底部右側窗格中:

http://jsfiddle.net/mRsvc/4/

這是函數,基本上超時只得到了最後一個值在循環中,我已經看到過,我確定如果我不那麼神經質,它可能會更簡單。這裏有特別的功能:

function update() 
     { 
      var i; 
      this.context.lineWidth = BRUSH_SIZE;    
      this.context.strokeStyle = "rgba(" + COLOR[0] + ", " + COLOR[1] + ", " + COLOR[2] + ", " + BRUSH_PRESSURE + ")"; 
      for (i = 0; i < scope.painters.length; i++) 
      { 
       scope.context.beginPath(); 
       var dx = scope.painters[i].dx; 
       var dy = scope.painters[i].dy; 
       scope.context.moveTo(dx, dy); 
       var dx1 = scope.painters[i].ax = (scope.painters[i].ax + (scope.painters[i].dx - scope.mouseX) * scope.painters[i].div) * scope.painters[i].ease; 
       scope.painters[i].dx -= dx1; 
       var dx2 = scope.painters[i].dx; 
       var dy1 = scope.painters[i].ay = (scope.painters[i].ay + (scope.painters[i].dy - scope.mouseY) * scope.painters[i].div) * scope.painters[i].ease; 
       scope.painters[i].dy -= dy1; 
       var dy2 = scope.painters[i].dy; 
       scope.context.lineTo(dx2, dy2); 
       scope.context.stroke(); 
       for(j=FADESTEPS;j>0;j--) 
       { 
        setTimeout(function() 
         { 
          var x=dx,y=dy,x2=dx2,y2=dy2; 
          scope.context.beginPath(); 
          scope.context.lineWidth=BRUSH_SIZE+1; 
          scope.context.moveTo(x, y); 
          scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")"; 
          scope.context.lineTo(x2, y2); 
          scope.context.stroke(); 
          scope.context.lineWidth=BRUSH_SIZE; 
         }, 
        DURATION/j); 
       } 
      } 
     } 
+0

[Javascript閉包內循環 - 簡單實用示例]的可能重複(http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – rds 2013-01-17 17:55:58

回答

2

的問題是,你是指在函數中的變量dxdy,等你傳遞給setTimeout()周邊範圍的定義和時間的任何實際的超時運行這些變量都保存循環的最後一次迭代的值。

您需要創建一個額外的包含函數來關閉每次迭代的值。你可以試試下面的:

for(j=FADESTEPS;j>0;j--) { 
    (function(x,y,x2,y2) { 
     setTimeout(function() { 
     scope.context.beginPath(); 
     scope.context.lineWidth=BRUSH_SIZE+1; 
     scope.context.moveTo(x, y); 
     scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")"; 
     scope.context.lineTo(x2, y2); 
     scope.context.stroke(); 
     scope.context.lineWidth=BRUSH_SIZE; 
     }, 
     DURATION/j); 
    })(dx, dy, dx2, dy2); 
} 

這爲j=FADESTEPS循環的每個迭代一個新的匿名函數,立即執行,並經過dx等價值觀,因爲他們在當時的環跑的每次迭代,並將x,y等變量移出現有函數,並將它們作爲新函數的參數,然後在超時運行時使用正確的值。

0

或者另一種方式(只要你不使用IE瀏覽器,但讓它在第一次學習帆布:))

for(j=FADESTEPS;j>0;j--) 
{ 
    setTimeout(function(x,y,x2,y2) 
    { 
     scope.context.beginPath(); 
     scope.context.lineWidth=BRUSH_SIZE+1; 
     scope.context.moveTo(x, y); 
     scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")"; 
     scope.context.lineTo(x2, y2); 
     scope.context.stroke(); 
     scope.context.lineWidth=BRUSH_SIZE; 
    }, 
    DURATION/j,dx,dy,dx2,dy2); 
} 

PS:有是一套額外的功能,不需要(原因是顯而易見的)

1

你可以嘗試這樣的事情:

`<script> 
for(j=10;j>0;j--) 
       { 
       var fn = function(ind){return function() 
         { 
          console.log(ind); 
         }; 
         }(j); 
        setTimeout(fn, 
        1000); 
       } 
</script>` 
0
  1. 所有j的首先是全球性的。
  2. 其次,你永遠不會關閉你開始的路徑,這會導致內存泄漏。這似乎很慢,這可能是爲什麼。你需要撥打closePath(),只要你完成了你開始的路徑beginPath()
  3. 接下來,我認爲這是如何工作的一些普遍的樂趣。通過用白色繪製最後一件東西,你漸漸淡出。我之前做過類似的事情,但是我清理了整個屏幕,並不斷重複繪製一些東西。它爲我工作很好。

說明從更高的範圍傳遞

dxdy其他的答案是正確的答案,但。同步for循環中定義的異步函數將採用狀態的最後一個版本。

for (var i = 0; i < 10; i++) setTimeout(function() { console.log(i)}, 10) 
10 
10 
// ... 
0

我建議你使用一個數組並存儲點,避免setTimeOut調用循環。有點像這樣。

this.interval = setInterval(update, REFRESH_RATE); 

    var _points = []; 

    function update() { 
     var i; 
     this.context.lineWidth = BRUSH_SIZE; 
     this.context.strokeStyle = "rgba(" + COLOR[0] + ", " + COLOR[1] + ", " + COLOR[2] + ", " + BRUSH_PRESSURE + ")"; 
     for (i = 0; i < scope.painters.length; i++) { 
      scope.context.beginPath(); 
      var dx = scope.painters[i].dx; 
      var dy = scope.painters[i].dy; 
      scope.context.moveTo(dx, dy); 
      var dx1 = scope.painters[i].ax = (scope.painters[i].ax + (scope.painters[i].dx - scope.mouseX) * scope.painters[i].div) * scope.painters[i].ease; 
      scope.painters[i].dx -= dx1; 
      var dx2 = scope.painters[i].dx; 
      var dy1 = scope.painters[i].ay = (scope.painters[i].ay + (scope.painters[i].dy - scope.mouseY) * scope.painters[i].div) * scope.painters[i].ease; 
      scope.painters[i].dy -= dy1; 
      var dy2 = scope.painters[i].dy; 
      scope.context.lineTo(dx2, dy2); 
      scope.context.stroke(); 
      _points.push([dx, dy, dx2, dy2]); 

      clear(); 
     } 
    } 

    function clear(){ 

     if(_points.length < FADESTEPS){ 
      return; 
     } 

     var p = _points.shift(); 
        if(!p){ 
         return; 
        } 
        var x = p[0], 
         y = p[1], 
         x2 = p[2], 
         y2 = p[3]; 
        scope.context.beginPath(); 
        scope.context.lineWidth = BRUSH_SIZE + 1; 
        scope.context.moveTo(x, y); 
        scope.context.strokeStyle = "rgba(" + 255 + ", " + 255 + ", " + 255 + ", " + .3 + ")"; 
        scope.context.lineTo(x2, y2); 
        scope.context.stroke(); 
        scope.context.lineWidth = BRUSH_SIZE; 

    } 

我知道這不完全是你需要的,但我認爲這可以修改得到它。