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をやっている人間なので、このようなお題で書くと、言葉足らずだったり、今回のように逆に冗長になったりしてしまうのですが、この件に関しては後ほどもう少し書いてみるつもりです。