『 [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スコープは移動しないので便利。
あと、メソッドと関数の使い分けは適当なので突っ込まないでね。

« 
» 

Leave a Reply