这是处理 JavaScript/ActionScript 函数时的常见错误。您遇到了问题,因为函数是闭包,这意味着它们在定义函数时持有对范围内定义的变量的引用。
这意味着您的匿名处理函数在变量周围关闭i
,但它存储对它的引用,而不是它的值。由于i
变化,每个函数都持有对同一个变量的引用,该变量将只保存分配给它的最后一个值。
基本上,如果要关闭变量的特定值,则必须在函数范围内声明变量(使用语句)。var
因此,这看起来应该可以工作:
for (var i:int = 0; i < 10; i++) {
var scopedI:int = i;
mc[i].addEventListener(MouseEvent.CLICK, function (e:MouseEvent) { trace(scopedI); });
}
我们在循环的范围内声明了一个新变量 ,scopedI
以专门关闭该值,因为该变量将在循环的每次迭代中重新声明为唯一值。不幸的是,ActionScript 和 JavaScript 一样,没有块级作用域,只有函数级作用域,所以所有的变量声明都被“提升”到了函数的顶部。
这几乎只是意味着您的类型与在该函数中声明的任何其他变量scopedI
具有相同的范围。i
那么,我们怎样才能创建一个新的范围呢?具有更多功能。请记住,在 ActionScript 中,函数是对象,因此我们可以做如下疯狂的事情:
(function (id) {
return function () { trace(id); };
})(7);
那段代码创建了一个函数,然后立即使用参数值执行7
它id
。这很有用,因为 nowid
的作用域是我们返回的内部函数,所以无论外部发生什么,该函数总是会打印“7”。
同样,我们可以使用它来限定i
循环中的变量。您的代码可以更新为如下所示:
function createMarkers(mapLocations){
var markerArray:Array = new Array();
for(var i = 0; i < mapLocations.length; i++){
markerArray.push(new marker());
markerArray[i].x = mapLocations[i][1];
markerArray[i].y = mapLocations[i][2];
markerArray[i].markerText.text = mapLocations[i][0].toString();
markerArray[i].addEventListener(MouseEvent.CLICK, (function (scopedI) {
return function (e:MouseEvent) { clickTarget(e, scopedI); };
})(i));
bgImage.addChild(markerArray[i]);
}
}
function clickTarget(e:MouseEvent, a){
trace(a);
}
现在,scopedI
每次迭代都是唯一的。是的,语法有点混乱,但这最终成为语言的一个非常强大和富有表现力的特性。如果你能理解它,它会非常有用。