Flash AS3功能跟踪相同的值

时间:2012-12-24 21:20:04

标签: actionscript-3 flash

有人可能会解释为什么下面的曲线会返回数组的长度而不是数组项中“i”的值吗?

非常感谢,尼克

AS3

function createMarkers(mapLocations){
    var markerArray:Array = new Array();
    for(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(e:MouseEvent){clickTarget(e,i);});
        bgImage.addChild(markerArray[i]);
    }
}

function clickTarget(e:MouseEvent,a){
    trace(a);
}

3 个答案:

答案 0 :(得分:4)

处理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执行它。这很有用,因为现在id的范围限定为我们返回的内部函数,因此无论外部发生什么,该函数将始终打印“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对于每次迭代都是唯一的。是的,语法有点混乱,但这最终成为该语言非常强大和富有表现力的特征。如果你能理解它,它非常有用。

答案 1 :(得分:1)

添加Alexis所说的,

由于您要添加Click事件,我假设该项目是显示对象。

与Javascript不同,您还可以将项目命名为&amp;在处理程序中检索它,如:

        ...
        markerArray[i].name = "marker" + i; 
        markerArray[i].addEventListener(MouseEvent.CLICK, clickTarget);
        bgImage.addChild(markerArray[i]);
    }
}

function clickTarget(e:MouseEvent){
    var a = e.currentTarget.name.substr(6);
    trace(a);
}

当然,假设name属性直到现在都没用。

答案 2 :(得分:-1)

因为您的内联鼠标事件正在捕获变量 i(引用)而不是其值。

试试这个:

function createMarkers(mapLocations){
    var markerArray:Array = new Array();
    for(var i:Number = 0; i<mapLocations.length; i++){
        var thisI:Number = i;
        markerArray.push(new marker());
        markerArray[thisI].x=mapLocations[thisI][1];
        markerArray[thisI].y=mapLocations[thisI][2];

        markerArray[thisI].markerText.text = mapLocations[thisI][0].toString();
        markerArray[thisI].addEventListener(MouseEvent.CLICK,
            function(e:MouseEvent){
                clickTarget(e,thisI);
            });
        bgImage.addChild(markerArray[thisI]);
    }
}

这应该有效,因为每次迭代循环都会重新创建thisI