LoginSignup
1
1

More than 3 years have passed since last update.

Flash Advent Calendar 6日目 - クロージャのスコープ問題 -

Last updated at Posted at 2020-12-06

今日はちょっと小休憩的な感じで書きたいと思います。

FlashのActionScriptをエミュレーションする中で
クロージャーのスコープ問題にぶつかりました。

JavaScriptの実装になれていればすんなり解決していたと思うのですが・・・

ActionScriptサンプル


import flash.display.MovieClip;
import flash.events.Event;

public class Main extends MovieClip
{
    public function Main ()
    {
        super();
        this.addEventListener(Event.ENTER_FRAME, this._onEnterFrame);
    }

    private function _onEnterFrame ()
    {
        trace(this);
    }
}

_onEnterFrameで出力される情報は

[object Main]

つまり、スコープはクラスに向いています。

これが、JavaScriptだと

new Main(); // <= [Window]が出力される

と、globalのwindowクラスに向いてしまいます。

当時、ここが全然理解できず結構苦戦しました。。。
JavaScript - MDN - Mozillaを徘徊してbindを見つけました。

bind() メソッドは、呼び出された際に this キーワードに指定された値が設定される新しい関数を生成します。
この値は新しい関数が呼び出されたとき、一連の引数の前に置かれます。

ActionScriptをエミュレートするには、JavaScript側でthis._onEnterFrame関数に対してbind(this)をコールしてスコープを確約させる必要があります。

this.addEventListener(Event.ENTER_FRAME, this._onEnterFrame.bind(this));

解決してしまえば、それほど大きな問題ではないのですが
当時は結構苦戦しました。。。

また、この後、ActionScriptのaddEventListenerの仕様で
同一のスコープで、同一の関数は追加しない。っという仕様にぶつかったのですが
きっとJavaScriptだけで実装していれば関わらない仕様だと思うのでサラッと書きます。

ドキュメントにあるようにbind関数をコールすると新しい関数が生成されます。

const method = this._onEnterFrame.bind(this);
console.log(method === this._onEnterFrame); // false

既存の関数から新たにスコープが確約された関数が生成されます。
なので、元の関数と生成された関数は別物として扱われます。

こういった、ActionScriptとJavaScriptの挙動の違いを詰めていく調査と検証に大きな時間がかかってしまいました。

ただ、その副産物でJavaScript特有の仕様や機能など知る事もできたので
言語を理解するという点ではとても勉強になり
今でも仕事で役に立っているので結果オーライですw

明日は、WebWorkerに関して書こうと思います!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1