ダイナミックプロパティ

昨日は勉強会でした。
AS2とAS3のダイナミックプロパティの話が出たのですが、自分の記憶がイマイチ定かではなかったので、もう一度調べてみました。

AS3には、sealedクラスとdynamicクラスがあり、

  • sealedクラス・・・通常のクラスでプロパティやメソッドの動的追加は不可
  • dynamicクラス・・・動的にプロパティやメソッドをつけかえられるクラスで、プロパティやメソッドの動的追加が可能

という違いがあります。
dynamicクラスを作成するには、クラス宣言時に「dynamic」というキーワードをつけてやればOKです。

 //通常のクラス宣言(sealedクラス)
 public class SealedClass{
 }
 //ダイナミッククラス宣言(dynamicクラス)
 public dynamic class DynamicClass{
 }

dynamic宣言をしておくと、インスタンスごとに好き勝手にプロパティやメソッドが追加が出来る反面、コンパイル時にエラーが出ないという欠点があります。
dynamicかどうかは、最終的にインスタンス化するときのクラス宣言によるようで、例えば上記DynamicClassを継承したSealedクラスを作成すると、そのクラスのインスタンスはSealedクラスになります。逆の関係も成り立ちます。

dynamic宣言をしたクラスに対してプロパティやメソッドを追加するには、次のようにします。
表記法はdotで書く表記法と、連想配列で書く表記法があり、どちらも機能としては同じになります。

 //dot表記
 var dyna:DynamicClass = new DynamicClass();
 dyna.dynamicFunction1 = function():void{ //メソッド定義 };
 dyna.dynamicProperty1 = "プロパティ定義";
 //連想配列表記 
 dyna["dynamicFunction2"] = function():void{ //メソッド定義 };
 dyna["dynamicProperty2"] = "プロパティ定義";

 //実行 すべてOK
 dyna.dynamicFunction1();
 Alert.show(dyna.dynamicProperty1);
 dyna.dynamicFunction2();
 Alert.show(dyna.dynamicProperty2);
 dyna["dynamicFunction1"]();//dot表記を連想配列で呼び出しも出来る 逆もOK
 Alert.show(dyna["dynamicProperty2"]); 

sealedクラスに対して同様のプログラムを書いた場合、

という挙動になります。

 //dot表記 コンパイルエラーになる
 var sealed:SealedClass = new SealedClass ();
 sealed.dynamicFunction1 = function():void{ //メソッド定義 };
 sealed.dynamicProperty1 = "プロパティ定義";
 //連想配列表記 コンパイルは通るが実行時にエラーになる
 sealed["dynamicFunction2"] = function():void{ //メソッド定義 };
 sealed["dynamicProperty2"] = "プロパティ定義";

 //実行 すべてNG
 sealed.dynamicFunction1();
 Alert.show(sealed.dynamicProperty1);
 sealed["dynamicFunction2"]();
 Alert.show(dyna["dynamicProperty2"]);

AS2にはそういった区別はなく、すべてAS3のDynamicクラスとして扱えます。ただし、AS2の場合は、変数に型宣言がある場合はdot表記をコンパイルエラーにします。

 //dot表記 コンパイルエラーになる
 var sealed:SealedClass = new SealedClass ();
 sealed.dynamicFunction1 = function():Void{ //メソッド定義 };
 sealed.dynamicProperty1 = "プロパティ定義";
 //連想配列表記 コンパイルは通り、実行可能
 sealed["dynamicFunction2"] = function():Void{ //メソッド定義 };
 sealed["dynamicProperty2"] = "プロパティ定義";
 
 //Objectにキャスト、もしくは型指定なしにするとdot表記もOK
 Object(sealed).dynamicFunction1 = function():Void{ //メソッド定義 };
 var objs = sealed;
 objs.dynamicFunction1 = function():Void{ //メソッド定義 };
 
 //実行
 sealed.dynamicFunction1();//コンパイルエラー
 sealed["dynamicFunction1"];//実行OK
 Object(sealed).dynamicFunction1();//実行OK
 objs.dynamicFunction1()://実行OK

AS3は、インスタンス化する際にSealedであるかどうかを判断し、Sealedである場合はdynamicに必要な機能をメモリ上に展開しないことでパフォーマンスをあげているそうです。
なので、AS2からAS3に移行する場合、AS2でやっていたような「最後はダイナミックでなんとかする」的なコーディングが使えない場合があるので、その点は注意が必要かもしれません。

#AS3のテストサンプル http://hatena.souko105.net/20070413/DynamicSample.zip

#昨日はAS3でも連想配列表記でダイナミックにプロパティをつけられるはず、と豪語していましたが、家に帰って調べてみたら、連想配列表記でプロパティをつけていたクラスがflash.net.URLValiablesというクラスで、このクラスはdynamic宣言されていました。大変失礼致しましたm(_ _)m