Javascript将参数传递给循环内的setTimeout函数

Javascript将参数传递给循环内的setTimeout函数,javascript,loops,Javascript,Loops,我试图在Javascript中的for循环内执行setTimeout()函数,但我得到了错误“shape未定义”,即使它已定义,我将其作为setTimeout()调用中函数的参数传递。如果我删除setTimeout存储模块,该函数就可以正常工作 为什么我会出现这个错误?我如何修复它 谢谢 function fadeShapes(layer, movement, opacity, speed) { var shapes = layer.getChildren(); for(var

我试图在Javascript中的for循环内执行setTimeout()函数,但我得到了错误“shape未定义”,即使它已定义,我将其作为setTimeout()调用中函数的参数传递。如果我删除setTimeout存储模块,该函数就可以正常工作

为什么我会出现这个错误?我如何修复它

谢谢

function fadeShapes(layer, movement, opacity, speed) {
    var shapes = layer.getChildren();

    for(var n = 0; n < shapes.length; n++) {
        var shape = layer.getChildren()[n];
        setTimeout(function(shape){
            shape.transitionTo({
                alpha: opacity,
                duration: speed
            }); 
        }, 100);                
    }
}
功能Fadeshape(图层、移动、不透明度、速度){
var shapes=layer.getChildren();
对于(var n=0;n
这是一个常见的关闭问题,下面是固定代码:

function fadeShapes(layer, movement, opacity, speed) {
    var shapes = layer.getChildren();

    for(var n = 0; n < shapes.length; n++) {
        var shape = layer.getChildren()[n];
        setTimeout((function (bound_shape) {
            return function() {  // return function!
                bound_shape.transitionTo({
                    alpha: opacity,
                    duration: speed
                }); 
            };
        }(shape)) // immediate execution and binding
        , 100);                
    }
}
功能Fadeshape(图层、移动、不透明度、速度){
var shapes=layer.getChildren();
对于(var n=0;n
代码中发生的情况是,for循环将运行,
n
函数将在
100ms
中从执行开始调度,但是
shape
的值会更改!因此,当调用回调时,
shape
shapes[length-1]
(最后一个形状)的值


要修复它,必须使用闭包“关闭”该值。在这种情况下,绑定
shape
值并返回要在
100ms

JavaScript中执行的函数的函数没有块作用域,因此所有超时函数都指向同一个变量
shape
,循环完成后该变量指向数组的未定义索引。您可以使用匿名函数来模拟要查找的范围:

for(var n = 0; n < shapes.length; n++) {
    var shape = shapes[n]; //Use shapes so you aren't invoking the function over and over
    setTimeout((function(s){
        return function() { //rename shape to s in the new scope.
            s.transitionTo({
                alpha: opacity,
                duration: speed
            });
        };
    })(shape), 100);   
}

forEach
内置于现代浏览器中,但可以在Internet Explorer的旧浏览器中进行填充。

以下是迭代器的代码,它考虑了
100ms
延迟。(未经测试)

函数迭代(数组、超时、回调){
var n=0,length=array.length;
函数步骤(){
回调(数组[n]);
n+=1;
如果(n*/、不透明度、速度){
var shapes=layer.getChildren();
迭代(形状,100,函数(形状){
形转换({
α:不透明度,
持续时间:速度
}); 
});
}

请注意,通过以这种方式使用
iterate
函数,也可以解决闭包问题。

如果希望setTimeout调用间隔100毫秒执行,则只需在每个set Timeout调用中添加100毫秒:

function fadeShapes(layer, movement, opacity, speed) {
    var shapes = layer.getChildren();

    for(var n = 0; n < shapes.length; n++) {
        var shape = shapes[n];
        setTimeout((function(local_shape){
            return function(){
                local_shape.transitionTo({
                    alpha: opacity,
                    duration: speed
                });
             } 
        })(shape), 100 + n*100);                
    }
}
功能Fadeshape(图层、移动、不透明度、速度){
var shapes=layer.getChildren();
对于(var n=0;n
试试:

功能Fadeshape(图层、移动、不透明度、速度){
var shapes=layer.getChildren();
对于(var n=0;n
请注意,所有setTimeout调用都将设置为在100毫秒延迟后同时运行(给或拿一两毫秒),它们不会间隔100毫秒运行。你明白我的意思了吧,罗伯!如何实现您描述的功能?@j-man86我已经添加了一个详细说明解决方案的答案。@j-man86-您可以按照Greg的建议使用递增计数器在循环中设置它们,或者您可以让每一个调用下一个,直到达到某个限制。
+1
使用“块范围”<代码>变量形状
实际上被“提升”到函数的开头,在最初的问题中,循环结束后,
shape
指向什么并不重要,因为当超时函数触发时,
shape
完全超出范围。@kojiro:JavaScript中的作用域不是这样的。函数永远不会失去它原来的作用域。JavaScript函数是闭包,这意味着无论在何处调用它们,它们都会携带其原始作用域。@amnotiam yes,并且带有值的
shape
与传递给
setTimeout
@kojiro:Right的函数参数
shape
不同。该参数未定义。它需要将值传递给它,或者将其删除,这将给我们留下
fadeShapes
函数范围中的
shape
。。。您认为哪一种效率更高?就性能而言,
setInterval
setTimeout
之间没有太大区别<如果由于调用堆栈上的限制而迭代大量元素,
setTimeout
可能会出现问题,
setInterval
不存在此问题。只要确保完成后清除计时器(
clearInterval
function iterate(array, timeout, callback) {
    var n = 0, length = array.length;
    function step() {
        callback(array[n]);
        n += 1;
        if (n < length) {   // are there more elements?
            setTimeout(step, timeout);
        }
    }
    setTimeout(step, timeout);  // start
}

function fadeShapes(layer, movement /* unused> */, opacity, speed) {
    var shapes = layer.getChildren();
    iterate(shapes, 100, function (shape) {
        shape.transitionTo({
            alpha: opacity,
            duration: speed
        }); 
    });
}
function fadeShapes(layer, movement, opacity, speed) {
    var shapes = layer.getChildren();

    for(var n = 0; n < shapes.length; n++) {
        var shape = shapes[n];
        setTimeout((function(local_shape){
            return function(){
                local_shape.transitionTo({
                    alpha: opacity,
                    duration: speed
                });
             } 
        })(shape), 100 + n*100);                
    }
}
function fadeShapes(layer, movement, opacity, speed) {
    var shapes = layer.getChildren();

    for(var n = 0; n < shapes.length; n++) {
        var shape = layer.getChildren()[n];
        (function(sh) {
            setTimeout(function(){
                sh.transitionTo({
                    alpha: opacity,
                    duration: speed
                }); 
            }, 100); 
        })(shape);
    }
}