Activationオブジェクトについてもう少し考えてみました
前回のエントリーの、「関数内で定義したイベントハンドラから、参照できないはずのローカル変数の値がいつまでも参照できちゃう件」について、Activationオブジェクトなるものについて、改めて僕なりに理解を試みてみました。まずは、おさらいから。
【こんな状況】
1. FLASHのステージに"my_btn"というインスタンス名でボタンオブジェクトを配置。
2. ルートのフレームアクションに、以下のように記述。
hoge(); function hoge() { var localVar = "flash"; my_btn.onRelease = function() { trace (localVar); } }
3. my_btnをクリックすると、出力パネルにローカル変数の値"flash"が出力される。
【僕の理解】
1. ローカル変数localVarは関数hoge()が実行されると、メモリから自動的に消去されるはず。だってローカル変数というのは、そういうものだと教わったし。
2. my_btnをクリックした時点で、既に関数hoge()は実行済みなわけだから、ローカル変数localVarの値は空っぽ。だから、出力パネルにはundefinedが表示されるか、あるいは何も表示されないはず。
【野中さんの解説を読んだ後の僕の理解】
1. 関数hoge()が実行されると、Activationオブジェクトというオブジェクトが自動的に生成され、ローカル変数localVarはそのオブジェクトのプロパティ(のようなもの)に保存される。
2. そもそもActivatioinオブジェクトは何のためにあるのか?
→ローカル変数を関数毎に別のものとして扱うために生成される。これが異なる関数毎に生成され、その関数内のローカル変数を管理してくれているおかげで、異なる関数内で同じ名前の変数を使用しても問題が起きない。
3. そこで問題となるのは、関数を入れ子にした場合。つまり関数内で別の関数を定義しているケース。上記の例では関数hoge()内で、my_btnのイベントハンドラを匿名関数として定義しているわけですが、この匿名関数は自分自身を定義している大本の関数=hoge()のActivationオブジェクトを参照することができる。
4. さらに。大本のローカル変数=localVarを参照する関数(この場合はmy_btnに定義される匿名関数)が、イベントハンドラメソッドとして定義されると、通常は関数の実行後に自動的にガベージコレクションによって削除されるActivationオブジェクトが削除されないという、言語仕様になっている。
5. 結果としてmy_btnは、メモリに残ったままのローカル変数をいつまでも参照することができる。
試しに、入れ子構造をとらないで、以下のように"my_btn"のイベントハンドラを関数hoge()の外側で定義すると、my_btnをクリックしてもlocalVarの値はundefinedとして出力されます。これはmy_btnが、hoge()のActivationオブジェクトを参照できないためだと思われます。
function hoge() { var localVar = "flash"; } my_btn.onRelease = function() { trace (localVar); }
また、イベントハンドラの設定をメインのフレームアクションではなく、my_btnのボタンアクションに直接記述しても、同様の結果となります。
on(release) { trace (localVar); }
まぁ、当たり前の結果かもしれませんが、僕は感覚的にしか理解できていなかったので、Activationオブジェクトなるものの存在を意識した上で考えてみると、「あぁ、なるほどね」と思えてきました。
普段はPhotoshopとかHTMLをやっている人間なので、このようなお題で書くと、言葉足らずだったり、今回のように逆に冗長になったりしてしまうのですが、この件に関しては後ほどもう少し書いてみるつもりです。