無名イベントリスナの作成時の注意点

イベントリスナを関数内のローカル変数として作成することは多々ある。例えば、以下のようなコードだ。このコードは、ファイルパスを与えて、対象のファイルをロードする関数である。ロードの実行には、メモリ上に確保された 1 つのローダを使い回している。

function loadSomething(path:String):Void {
var listener:Object = new Object();
listener.onLoad = function(event:Object):Void {
trace("loaded");
};
this.fooLoader.addEventListener("onLoad", listener);
this.fooLoader.load(path);
}

このイディオムは手軽で強力なのだが、リスナをイベントソースから削除していないので痛い目を見る。上記の loadSomething() を n 回実行した場合、trace の総数は n ではなく、等差数列 (a1+an)n/2 に従って増加してゆく。

では、ローカル変数として定義したリスナを削除するにはどうすればよいか。コードを下記のように変更すればよい。

function loadSomething(path:String):Void {
var listener:Object = new Object();
listener.onLoad = function(event:Object):Void {
event.target.removeEventListener(event.type, this);
trace("loaded");
};
this.fooLoader.addEventListener("onLoad", listener);
this.fooLoader.load(path);
}

event.target は fooLoader を意味し、event.type は onLoad に等しい。つまり、イベント発生時にリスナが破棄されることになる。

ロードイベントのような一過性のイベントでは、ローダ自体もローカル変数として定義する方法がある。しかし、ロードを中断させる際などに、ローダへのアクセスが困難となるデメリットもある。