我正在尝试在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);
}
}
答案 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);
}
}