これは、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
その値を具体的に閉じます。これは、その変数がループの反復ごとに一意の値で再宣言されるためです。残念ながら、JavaScriptと同様に、ActionScriptにはブロックレベルのスコープがなく、関数レベルのスコープしかないため、すべての変数宣言は関数の先頭に「持ち上げられ」ます。
これは、タイプが、、およびその関数内で宣言された他の変数と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
反復ごとに一意になります。はい、構文は少し厄介ですが、これは言語の非常に強力で表現力豊かな機能になります。あなたがそれを理解することができれば、それは非常に役に立ちます。