4

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

5 回答 5

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较旧的浏览器中填充。

于 2012-08-06T00:13:46.410 回答
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更改的值!所以当你的回调被调用时shapeshapes[length-1](最后一个形状)的值。

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

于 2012-08-06T00:13:00.820 回答
0

如果您希望 setTimeout 调用间隔 100 毫秒执行,那么您只需将 100 毫秒添加到每个 set Timeout 调用:

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);                
    }
}
于 2012-08-06T01:38:59.477 回答
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);
    }
}
于 2012-08-06T03:51:43.670 回答
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以这种方式使用该函数,也可以解决关闭问题。

于 2012-08-06T00:28:41.807 回答