2011-09-13 11 views
0

コールバック関数内でクラスのメソッドを呼び出すと、thisオブジェクトを使用できません。
メソッドを呼び出すには、thatという変数を宣言し、thisthatに割り当て、コールバック内でthatを使用してthisというメソッドを呼び出します。

actionscriptでは、javascriptと同じようにする必要がありますか?

次のコードは、thatを使用してコールバック内のメソッドを呼び出す例です。
actionscriptの方が簡単ですか?
actionscriptのコールバック関数内でクラスのメソッドを使う方法は?

class C { 
    private var that:C; 

    function C() { 
     that = this 
    } 

    public function f1():void { 
     var sp:Sprite = new Sprite; 

     sp.addEventListener(MouseEvent.CLICK, function():void { 
      this.f2(); // this doesn't work 
      that.f2(); // that works 
     }); 
    } 

    public function f2():void { 
     trace('hello'); 
    } 
} 
+2

「this」を除外してみませんか? – OXMO456

+0

@ OXMO456ありがとうございます。 'this'を省略するとうまくいった。それは非常に簡単な解決法です。 –

答えて

5

は、ここでそれを行うための別の方法です:

package some.package { 
    class SomeSprite extends Sprite { 
     public function f1():void 
     { 
      var sprite1:Sprite = new Sprite; 
      sprite1.addEventListener(MouseEvent.CLICK, 
       (new Closure(f2, this, ["Hello"], sprite1).handler)); 

      var sprite2:Sprite = new Sprite; 
      sprite2.addEventListener(MouseEvent.CLICK, 
       (new Closure(f2, this, ["Bye Bye"], sprite2).handler)); 
     } 

     private function f2(message:String):void 
     { 
      trace(message); 
     } 
    } 
} 

class Closure { 
    public var callback:Function; 
    public var thisObj:Object; 
    public var params:Array; 
    public var dispatcher:IEventDispatcher; 
    public var cleanAfterCallback:Boolean = true; 

    function Closure(callback:Function, thisObj:Object, 
     params:Array, dispatcher:IEventDispatcher) 
    { 
     this.callback = callback; 
     this.thisObj = thisObj; 
     this.params = params; 
     this.dispatcher = dispatcher; 
    } 

    public function handler(e:Event):void 
    { 
     callback.apply(thisObj, params); 

     if (cleanAfterCallback) 
      dispatcher.removeEventListener(e.type, eventHandler) 
    } 
} 
+1

実際にクロージャを使う必要があるなら、これは本当に素晴らしい解決策です。そうでなければ、カスタムクラスを作成できます。MySpriteはSprite()を継承します。次に、このクラスに諺「メッセージ」を追加し、f1メソッドでsp1:MySprite = new MySprite();のようなコードを変更します。 sp1.message = "hello"; sp1.addEventListener(MouseEvent.CLICK、callback); sp2:MySprite =新しいMySprite(); sp2.message = "さようなら"; sp2.addEventListener(MouseEvent.CLICK、callback);コールバックでは、f2(MySprite(event.target).message)を呼び出すことができます。 –

1

あなたは、インライン関数クロージャを使用しているので、あなたが探しているthisはそのスコープになりません。これはjavascriptでクロージャを機能させるのと非常によく似ています(同じでない場合)。上記の方法は問題ありません。これを行うには他の方法もありますが、必ずしも簡単であるとは限らず、実装によって異なります。

function():void { 
     this.f2(); // this is scoped only to within this function 
     that.f2(); // that has reference to the global object this 
} 

あなたはトレース(これを)実行する場合は、[機能のグローバル]のようなものを言うだろう
Function Closures
Event listeners

0

のActionScriptドキュメントに以下をお読みください。それがうまくいかない理由です。

6

コールバック関数をクラスCのメソッドにすると、thisにアクセスすることができます。

public class C 
{ 
    private function f1():void 
    { 
     var sp:Sprite = new Sprite(); 

     sp.addEventListener(MouseEvent.CLICK, callback); 
    } 

    private function callback(event:MouseEvent):void 
    { 
     this.f2(); 
    } 

    private function f2():void 
    { 
     trace("Hello World"); 
    } 
} 

thisクラスCのインスタンスを参照し、その範囲は、全体クラスです。

+2

インラインクロージャは汚れていて、汚れたメモリリークもあります。 – divillysausages

+0

@Ivanお役に立つ情報ありがとうございます。 私はそれを知らなかった。もしf2( 'hello')を 'sp1'とf2(' hello ')に追加したいのであれば、 'f2()'にパラメータ '' f2(message:String):void {trace(message);} '')と 私はコールバックメソッド 'private function callbak(event:MouseEvent):void {th​​is.f2( 'hello');}を定義する必要があると思います。 } 'と 'プライベート関数callbak(イベント:MouseEvent):void {th​​is.f2( 'さようなら'); } '? これを行うより良い方法はありますか? –

+0

@divillysausagesインライン閉鎖メモリリークに関する情報をありがとう。 'addEventListener()'の直前の変数にインラインクロージャを割り当て、その変数をコールバックに使用するとします。 たとえば、 'var f:Function = function():void {th​​at.f2(); };このコードもインラインクロージャであり、メモリリークの原因になりますか?それとも清潔で安全ですか? –

2

アドビサイトのFunction Documentationを参照してください。 "thisArg"がメンバー関数を呼び出すオブジェクトと等しい "で"適用され、 "this"が正しいことを使用してください。

+0

ありがとうございました。 しかし、コールバック に 'apply'を使うことはできません。コールバックが発生したときに関数を実行するのではなく、' apply'がすぐに関数を実行するからです。 –

+0

@js_何** Fearnor **の意味は、私の答えでコードスニペットに書いたものです –

2

これが答えではありませんが、インラインクロージャ@js_によってコメント要求から、メモリリークしている理由を説明する方があります。

フラッシュでのメモリ管理は2通りあります。リファレンスカウントとマークとスイープ(詳細はhttp://divillysausages.com/blog/tracking_memory_leaks_in_as3をチェックしてください)。

メモリリークはaddEventListener()コールから発生します。既定では、addEventListenerは、リッスンしているオブジェクトへの参照を作成します。匿名関数はオブジェクトの参照を保持します。

弱いリスナーにすることはできますが、関数が匿名であるため、他の参照はありません。つまり、イベントリスナーが弱い場合、関数の最後にすべて収集されますローカル変数を使用しました)。

したがって、匿名関数を機能させるには、イベントリスナーを強くする必要があります。しかし、リスナーを削除するようになると、無名関数にアクセスすることができないので、それを削除することはできません。ベストケースのシナリオでは、コールバックに割り当てられたメモリが失われます。最悪のシナリオでは、匿名関数によるオブジェクトへの参照は、Flashがまだ使用中であると考えているため、オブジェクト自体が収集されない(連鎖する)ことを意味します。

イベントリスナー以外のオブジェクト自体に最終的に他の参照がない場合は、マークとスイープのフェーズ(このような循環参照を念頭に置いて設計されているため)の両方で収集する必要があります。つまり、あなたは本当にマークと掃引が必要ではない - それは地獄のように遅い(おそらくあなたのプログラムでは頻繁に休止することに気がつくだろう)、メモリ使用量が不足し始めるときだけである。参照カウントを自分で制御したい場合

+0

ありがとうございます。 マークとスイープを避けるために次の2つのアイデアはいかがですか? (1)例えば、sp.addEventListener(MouseEvent.CLICK、function():void {th​​at.f2();})のように、nullや他のオブジェクトでspを上書きすると思います。 sp = null;またはsp = anotherSprite; 'もremoveEventListener()を呼び出さずに、匿名関数への参照を削除します。 (2)addEventListener()の後に、spのメンバーに 'sp.f = function():void {th​​at.f2(); }; 'sp.addEventListener(MouseEvent.CLICK、sp.f);' 'sp.removeEventListener(sp.f);' –

+1

あなたが '' sp.f'のようなものに関数を格納すると、それはもはや匿名ではありません;)それは一般的ですアイデア。すべてのクラスで、リスナー、ヌル参照、クリア配列、辞書をクリアし、ステージからグラフィックスを削除し、それを実装する内部オブジェクトの 'destroy()'を呼び出す 'destroy()'関数を実装します。各オブジェクトは自身のクリーンアップを担当します。したがって、あなたの例では、 'sp.destroy();のようなものでしょう。 sp = null; 'オブジェクトが正常に消滅したかどうかを確認するのに役立つリンクに' MemoryTracker'クラスがあります – divillysausages

関連する問題