javascript变量范围/闭包在循环中超时后 [英] javascript variable scope/closure in loop after timeout

查看:68
本文介绍了javascript变量范围/闭包在循环中超时后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

晚了,道格拉斯·克罗克福德生活的我的大脑部分关闭了。 Ive尝试了一些东西,但没有像预期的那样做。



我有一个画布,我画了两条线,然后在定时器上淡出,只有最后一个线在循环中被淡出。这是我的小提琴,向下看到行中的50ish,看到它在动作中拖动鼠标在右下方窗格:



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.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);
}
}
}


解决方案>

问题是,在你传递的函数中引用的变量 dx dy 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 等移出现有函数,并使它们成为新参数那么到超时运行时,它将使用正确的值。


It's late and the part of my brain where Douglas Crockford lives is closed. Ive tried a few things but nothing's doing as expected.

I've got a canvas where I draw a 2 lines, then fade them out on a timer but only the last line in the loop is being faded out. Here's my fiddle, look down to line 50ish in the JS, to see it in action drag your mouse around in the bottom right pane:

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

this is the function, basically the timeout only gets the last value in the loop, I've seen this before and I'm sure if I wasn't so delirious it might be simpler. Here's the function in particular:

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);
                }
            }
        }

解决方案

The problem is that the variables dx, dy, etc that you refer to in the function you pass to setTimeout() are defined in the surrounding scope and by the time any of the timeouts actually runs these variables all hold the values from the last iteration of the loop(s).

You need to create an extra containing function to close over the values from each iteration. Try something like the following:

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);
}

This creates a new anonymous function for each iteration of the j=FADESTEPS loop, executing it immediately and passing the dx, etc. values as they were at the time each iteration of the loop ran, and moving the x, y, etc. variables out of your existing function and making them parameters of the new one so then by the time the timeout runs it will use the correct values.

这篇关于javascript变量范围/闭包在循环中超时后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆