『 [AS2] Delegate.create()の戻り値でハマる 』
2009 年 1 月 28 日AS2のthisはすぐに迷子になる。
trace("此処は"+this+"です"); //此処は_level_0です
button.onRelease = Delegate.create(this, function():Void {
trace("此処は"+this+"です"); //此処はbuttonです
});
Delegateを使えば、スコープがbuttonの中に入るのを防ぐことができる。
trace("此処は"+this+"です"); //此処は_level_0です
button.onRelease = Delegate.create(this, function():Void {
trace("此処は"+this+"です"); //此処は_level0です
});
Delegateのおかげでthisが迷子になることがない。
ちなみに僕はAS2でコーディングするときにはDelegateを鬼のように使う。「でぇ」で「Delegate.create(this, function():Void {});」を辞書登録してるくらいだから相当だと思う。今回はそのDelegateでちょっとだけハマったので書いておく。
経緯としてはEventDispatcherを使っていて、まずインスタンスメソッドを直接addEventListenerした。
hoge.addEventListener("event", Delegate.create(this, func));
同様に、Delegateを使って同じメソッドをremoveEventListenerしようとしたのだが何故かできなかった。
hoge.removeEventListener("event", Delegate.create(this, func));
そこでDelegate.createの実装を見てみると、新たに宣言したfという関数を返している事が分かった。細かい実装は気にしない。目を瞑ればそこはカプセル化。
static function create(obj:Object, func:Function):Function {
var f = function() {
var target = arguments.callee.target;
var func = arguments.callee.func;
return func.apply(target, arguments);
};
f.target = obj;
f.func = func;
return f;
}
つまり、インスタンスメソッドfuncとDelegate後の関数Delegate.create(this, func)とでは参照先が違っているということだ、多分。
trace(Delegate.create(this, func) == func);
//false
当然こういう事にもなる。
trace(Delegate.create(this, func) == Delegate.create(this, func));
//false
addEventListenerした関数とremoveEventListenerした関数の指すモノが違っているので正しくremoveEventListenerできていなかった。そこで、イベントリスナオブジェクトを介すことでaddEventListenerしたリスナをremoveEventListenerすることができた。
//イベントリスナの生成
var listener:Object = new Object();
//イベントリスナに関数を設定する
listener.func = Delegate.create(this, func);
//イベントリスナを登録するときはこう
addEventListener("event", listener);
//イベントリスナを削除するときはこう
removeEventListener("event", listener);
変数をふやすのが面倒でlistenerを使っていなかったし、脊髄反射でDelegateを使っていたので気をつけよう。
ちなみにAS3では何もしなくてもthisスコープは移動しないので便利。
あと、メソッドと関数の使い分けは適当なので突っ込まないでね。