イベントハンドラのスコープ

イベントハンドラ内で宣言や実行を行う変数やコマンドのスコープ (コンテキスト) は、使用しているイベントハンドラの種類によって異なります。つまり、イベントハンドラメソッドやイベントリスナーを使用している場合と、on() および onClipEvent() ハンドラを使用している場合では異なります。新しい ActionScript クラスのイベントハンドラを定義すると、イベントハンドラの定義に応じてスコープも変わります。ここでは、ActionScript 1.0 と ActionScript 2.0 の両方の例について説明します。

ActionScript 1.0 の例 自分で作成した ActionScript のすべての関数と同様に、イベントハンドラメソッドやイベントリスナーに割り当てられる関数ではローカル変数スコープが定義されますが、on() ハンドラおよび onClipEvent() ハンドラでは定義されません。

たとえば、次の 2 つのイベントハンドラを検討してみます。1 番目は clip_mc という名前のムービークリップに関連付けられた onPress イベントハンドラであり、2 番目は同じムービークリップインスタンスに割り当てられた on() ハンドラです。

// clip_mc の親クリップタイムラインに割り当てられている
clip_mc.onPress = function () {
    var shoeColor; // ローカル関数の変数
    shoeColor = "blue";
}
// clip_mc に割り当てられた on() ハンドラ :
on (press) {
    var shoeColor; // ローカル変数スコープではない
    shoeColor = "blue";
}    

どちらのイベントハンドラもコードは同じですが、結果は異なります。1 番目のハンドラの場合は、color 変数は、onPress 用に定義された関数にローカルな変数です。一方、2 番目のハンドラの場合、on() ハンドラがローカル変数スコープを定義しないため、この変数はムービークリップ clip_mc のタイムラインのスコープで定義されます。

ムービークリップにではなく、ボタンに割り当てられる on() イベントハンドラの場合、変数 (と関数呼び出しおよびメソッド呼び出し) がボタンインスタンスを含むタイムラインのスコープに呼び出されます。

たとえば、次の on() イベントハンドラをボタンオブジェクトに割り当てた場合とムービークリップオブジェクトに割り当てた場合とでは、結果は異なるものになります。前者の場合、play() 関数呼び出しは、ボタンを含むタイムラインの再生ヘッドを開始し、後者の場合、play() 関数呼び出しは、ハンドラを割り当てたムービークリップのタイムラインを開始します。

// ボタンに割り当てる。
on (press) {
    play(); // 親タイムラインを再生する。
}
// ムービークリップに割り当てる。
on (press) {
    play(); // ムービークリップのタイムラインを再生する。
}

ボタンオブジェクトに割り当てられると、play() 関数は、ボタンを含むタイムライン、つまり、ボタンの親タイムラインに適用されます。一方、on(press) ハンドラがムービークリップオブジェクトに割り当てられると、play() 関数呼び出しはそのハンドラを持つムービークリップに適用されます。次のコードをムービ―クリップに割り当てると、親タイムラインが再生されます。

// ムービークリップに割り当てる。
on (press) {
    _parent.play(); // 親タイムラインを再生する。
}

イベントハンドラ内またはイベントリスナー定義内では、同一の play() 関数が関数定義を含むタイムラインに適用されます。たとえば、my_mc ムービークリップインタンスを持つタイムラインで次の my_mc.onPress イベントハンドラメソッドを宣言するとします。

// タイムラインで定義された関数は 
my_mc.onPress = function () {
    play(); // 定義されているタイムラインを再生する。
};

onPress イベントハンドラを定義するムービークリップを再生するには、次のように、this キーワードを使用してそのムービークリップを明示的に参照してください。

// ルートタイムラインに定義されている関数は
my_mc.onPress = function () {
    this.play(); // my_mc クリップのタイムラインを再生する。
};

ただし、同じコードがボタンインスタンスのルートタイムラインに配置されていると、代わりにルートタイムラインが再生されます。

my_btn.onPress = function () {
    this.play(); // ルートタイムラインを再生する
};

イベントハンドラでの this キーワードのスコープの詳細については、this キーワードのスコープを参照してください。

ActionScript 2.0 の例 次のコードでは、TextLoader クラスを使用してテキストファイルをロードし、ファイルのロード完了後にテキストを表示します。

// TextLoader.as
class TextLoader {
    private var params_lv:LoadVars;
    public function TextLoader() {
        params_lv = new LoadVars();
        params_lv.onLoad = onLoadVarsDone;
        params_lv.load("http://www.helpexamples.com/flash/params.txt");
    }
    private function onLoadVarsDone(success:Boolean):Void {
        _level0.createTextField("my_txt", 999, 0, 0, 100, 20);
        _level0.my_txt.autoSize = "left";
        _level0.my_txt.text = params_lv.monthNames; // undefined
    }
}

このコードは、イベントハンドラのスコープに関して問題があるため正しく動作しません。thisonLoad イベントハンドラを参照しているのか、このクラスを参照しているのかが混同されています。onLoadVarsDone() メソッドが TextLoader オブジェクトのスコープで呼び出されることが前提のコーディングとなっていますが、このメソッドは TextLoader オブジェクトから取り出して LoadVars オブジェクトに移植されているため、実際には LoadVars オブジェクトのスコープで呼び出されます。テキストファイルのロードが正常に終了すると、LoadVars オブジェクトから this.onLoad イベントハンドラが呼び出され、続いて onLoadVarsDone() 関数が呼び出されます。このとき、this は TextLoader ではなく LoadVars に設定されています。params_lv オブジェクトは、呼び出されたとき、onLoadVarsDone() 関数が参照によって params_lv オブジェクトに依存しているにも関わらず、this スコープ内にあります。したがって、onLoadVarsDone() 関数は params_lv.params_lv というインスタンスにアクセスしようとしていることになりますが、これは実際には存在しません。

TextLoader オブジェクトのスコープの onLoadVarsDone() メソッドを正しく呼び出すには、次のようにします。関数リテラルを使用して、該当する関数を呼び出す匿名関数を作成します。owner オブジェクトが匿名関数のスコープで参照可能なため、呼び出す TextLoader オブジェクトの検索に使用できます。

// TextLoader.as
class TextLoader {
    private var params_lv:LoadVars;
    public function TextLoader() {
        params_lv = new LoadVars();
        var owner:TextLoader = this;
        params_lv.onLoad = function (success:Boolean):Void {
            owner.onLoadVarsDone(success);
        }
        params_lv.load("http://www.helpexamples.com/flash/params.txt");
    }
    private function onLoadVarsDone(success:Boolean):Void {
        _level0.createTextField("my_txt", 999, 0, 0, 100, 20);
        _level0.my_txt.autoSize = "left";
        _level0.my_txt.text = params_lv.monthNames; // 1 月、2 月、3 月、...
    }
} 

 

このページに新しいコメントが追加された場合に、電子メールでの通知を希望する。 | コメントレポート

現在のページ: http://livedocs.adobe.com/flash/9.0_jp/main/00000846.html