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

时间:2012-08-06 00:09:22

标签: javascript loops

我正在尝试在Javascript中的for循环中执行setTimeout()函数,但是我收到错误“shape is undefined”,即使它被定义了,我将它作为参数传递给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);                
    }
}

5 个答案:

答案 0 :(得分:12)

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

正如你可以通过我的问题来判断括号是否匹配,这可能有点棘手。这可以使用ES5 Array.forEach

进行清理
layer.getChildren().forEach(function(shape) { //each element of the array gets passed individually to the function
    setTimeout(function(shape){
        shape.transitionTo({
            alpha: opacity,
            duration: speed
        }); 
    }, 100);                
});

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

答案 1 :(得分:1)

这是一个常见的闭包问题,这里是固定代码:

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

代码中发生的情况是for循环将运行,n函数将在100ms中执行,但shape的值会发生变化!因此,当您的回调被调用时,shape的值为shapes[length-1](最后一个形状)。

要修复它,您必须使用闭包“关闭”该值。在这种情况下,一个函数绑定shape的值并返回您想要在100ms中执行的函数。

答案 2 :(得分:0)

这是一个尊重100ms延迟的迭代器的代码。 (另)

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

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

答案 3 :(得分:0)

如果你想让setTimeout调用相隔100ms执行,那么你只需要为每个设置超时调用添加100ms:

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

答案 4 :(得分:0)

尝试:

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