2

有人可以解释为什么下面的跟踪返回数组的长度而不是数组项中“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);
}
4

3 回答 3

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

那段代码创建了一个函数,然后立即使用参数值执行7id。这很有用,因为 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每次迭代都是唯一的。是的,语法有点混乱,但这最终成为语言的一个非常强大和富有表现力的特性。如果你能理解它,它会非常有用。

于 2012-12-24T22:55:01.097 回答
1

除了亚历克西斯所说的,

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

与 Javascript 不同,您还可以命名项目并在处理程序中检索它,例如:

        ...
        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 属性对您毫无用处。

于 2012-12-25T04:04:50.540 回答
-1

Because your inline mouse event is capturing the variable i (a reference) instead of its value.

Try this:

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

This should work because thisI is being recreated with each iteration of the loop.

于 2012-12-24T21:46:45.320 回答