[AS]イベントリスナー登録時にクロージャを使ってパラメータを渡すときの注意
通常マウスイベント等のリスナー関数には引数を持たすことができないが、クロージャ(←よくわかってないけど、関数の中に関数があるような状態のときみたい)を使うと、可能になります。
hakuhinさんの記事がわかりやすいと思います。
クロージャを使って関数にパラメータを保持する
このときに地雷があったのでご報告。
通常、こんな処理があったとします。
上の四角をクリックで、下のボタンにイベントを設定。
下のボタンをクリックすると上のボタンをクリックした回数が表示される。
//フレームアクション
//ボタン1となる四角を作成
var mc1:MovieClip = new MovieClip();
var mcg1:Graphics=mc1.graphics;
mcg1.beginFill(0xFFCC00);
mcg1.drawRect(0,0,100,50);
mcg1.endFill();
addChild(mc1);
mc1.buttonMode=true;
//ボタン2となる四角を作成
var mc2:MovieClip = new MovieClip();
var mcg2:Graphics=mc2.graphics;
mcg2.beginFill(0x88CC00);
mcg2.drawRect(0,0,100,50);
mcg2.endFill();
mc2.y=100;
addChild(mc2);
mc2.buttonMode=true;
//ボタン1クリック回数
var count:uint=0;
//ボタン位置のクリック動作
mc1.addEventListener(MouseEvent.CLICK, addMouseEvent);
function addMouseEvent(e:MouseEvent):void {
count++;
mc2.addEventListener(MouseEvent.CLICK,xClick);
trace(count);
}
function xClick(e:MouseEvent):void {
trace("count : "+count);
}
これをcountがローカル変数だったとして、クロージャ的に書くと
//フレームアクション
//ボタン1となる四角を作成
var mc1:MovieClip = new MovieClip();
var mcg1:Graphics = mc1.graphics
mcg1.beginFill(0xFFCC00);
mcg1.drawRect(0,0,100,50);
mcg1.endFill();
addChild(mc1);
mc1.buttonMode = true;
//ボタン2となる四角を作成
var mc2:MovieClip = new MovieClip();
var mcg2:Graphics = mc2.graphics
mcg2.beginFill(0x88CC00);
mcg2.drawRect(0,0,100,50);
mcg2.endFill();
mc2.y = 100;
addChild(mc2);
mc2.buttonMode = true;
//ボタン1クリック回数
var count:uint = 0;
//ボタン位置のクリック動作
mc1.addEventListener(MouseEvent.CLICK, addMouseEvent);
function addMouseEvent(e:MouseEvent):void{
count ++;
mc2.addEventListener(MouseEvent.CLICK,xClick(count));
trace(count);
}
function xClick(mc1):Function {
return function(e:MouseEvent):void {
trace("count : "+count);
}
}
実行するとわかるのですが、上の四角をクリックした回数だけ、下のボタンのイベントが重複します。
上の例ではどんだけ上の四角をクリックしても重複しなかったのですが、下の例では重複しまくります。
これ、気づくまでかなり時間かかりました・・・
まぁそもそもイベント登録が重複してしまう設計が悪いのでしょうけど・・・
ともかくクロージャってイベントリスナーに引数を持たせたいときはより厳密に設計しないとまずそうです。
Tweet