サイトトップ

Director Flash 書籍 業務内容 プロフィール

Macromedia Flash非公式テクニカルノート

ActionScript 2.0と1.0の継承について

ID: FN0504001 Product: Flash

Platform: All
Version: MX and Above

オブジェクト指向プログラミングにおける大きな特徴のひとつが、「継承」(inheritance)という仕組みです。「継承」とは、あるクラスをもとにして、別のクラスをつくることです。継承元のクラスをスーバークラス・親クラス・基本クラスなどといい、継承してつくられたクラスをサブクラス・子クラス・派生クラスなどといいます(Wikipedia「クラス」参照)。

継承は「拡張」(extension)と呼ばれることもあります。実際、ActionScript 2.0ではextendsというキーワードを使って、継承するスーパークラスを定義します。ActionScript 1.0では、Function.prototypeプロパティを使用して、継承を行います。

ActionScript 2.0のextendsキーワードの実装は、1.0の継承とは異なる点があります。それぞれの継承の内容と、ActionScript 2.0でFlash Player 6をターゲットとして書出した場合について簡単にご説明します。

1. ActionScript 1.0の継承
クラスのコンストラクタ関数を定義すると、関数にはFunction.prototypeプロパティが備わります。このブロパティにfunction(関数)やプロパティ(変数)を設定すると、クラスのメソッドとプロパティのデフォルト値が定義できます。

コンストラクタからつくられたインスタンスは、Object.__proto__プロパティをもちます。Object.__proto__プロパティは、コンストラクタ関数のFunction.prototypeプロパティを参照します。インスタンスをターゲットにしてメソッドやプロパティにアクセスしたとき、インスタンス自身がそれらを持ち合わせていなければ、Object.__proto__プロパティの参照先からメソッドやプロパティを呼出そうとします。

ActionScript 1.0においては、このようなコンストラクタ関数のprototypeとインスタンスの__proto__というふたつのプロパティを利用して、継承が行われます。スーパークラスのインスタンスを生成すると、そのインスタンスの__proto__プロパティは、スーパークラスのコンストラクタ関数のprototypeプロパティを参照します。したがって、このスーパークラスのインスタンスを、サブクラスのコンストラクタ関数のprototpeプロパティに設定すれば、サブクラスはスーパークラスを継承することになります[*1][*2]。

[*1] 詳しくは、Flash MX 2004 (7.2)オンラインヘルプ[ActionScriptユーザーガイド] > [ActionScript 1でのオブジェクト指向プログラミング] > [ActionScript 1について] > [ActionScript 1での継承の作成]またはFlash MXオンラインヘルプ[Flashの使用] > [ActionScript言語について] > [カスタムオブジェクトについて] > [継承の作成]をご参照ください。

[*2] Function.prototypeプロパティは、デフォルトではObjectクラスを継承します。

trace(MyClass.prototype instanceof Object); // 出力: true
trace(MyClass.prototype.__proto__ === Object.prototype); // 出力: true

// フレームアクション
// [1]コンストラクタ関数定義
function Subclass() {}
// [2]スーパークラスの継承
Subclass.prototype = new Superclass();
// [3]サブクラスにメソッドとプロパティを定義
// ...[後略]...

この継承方法を使う場合に注意すべき点は、第1にスーパークラスのインスタンスでサブクラスのFunction.prototypeブロパティを書替えていることです。したがって、サブクラスにプロパティやメソッドを定義する前に、継承は済ませておかなければなりません。そうしないと、プロパティやメソッドの設定されたFunction.prototypeブロパティを、上書きしてしまうことになります。

注意点の第2は、継承時に必ずスーパークラスを呼出す必要があることです。たとえば、サブクラスのインスタンスを生成するときに、初期設定値をスーパークラスに渡したい場合を考えてみましょう(スクリプト001)。

スクリプト001■サブクラスからスーパークラスに初期設定値を渡す

// フレームアクション
// [1]スーパークラス定義
function Superclass(prop) {
   this.prop = prop;
   trace("Superclass is called with "+prop);   // 確認用
}
// [2]サブクラス定義
function Subclass(prop) {
   super(prop);
}
Subclass.prototype = new Superclass();   // 継承
// [3]テスト: インスタンスの生成
var obj = new Subclass("my property");
// [出力](Flash Player 7書出し)
Superclass is called with undefined
Superclass is called with my property

サブクラスのコンストラクタからsuper演算子でスーパークラスを呼出す

[出力]の1行目は、継承を設定するときに、引数なしでスーパークラスが呼出された結果です。そして、2行目が、実際にインスタンスを生成する際の呼出しということになります。継承の設定時には、インスタンスを作成すること自体は目的ではありません。継承さえ行われればよいので、初期設定の処理は不要です[*3]。しかし、この継承時のスーパークラス呼出しは、やむを得ない副次的な効果といえます。

[*3] 無駄な初期設定は、引数の判定を加えれば回避できます。

function Superclass(prop) {
   if (prop != "inherit") {
     this.initialize();   // 初期設定用のメソッド呼出し
   }
}
function Subclass(prop) {
   super(prop);
}
Subclass.prototype = new Superclass("inherit");

なお、後掲「ActionScriptコーディングガイド」p.15「オブジェクトの継承」参照。

継承がサブクラスのコンストラクタ関数に備わるprototypeオブジェクトの__proto__プロパティにスーパークラスのコンストラクタのprototypeを設定することだとすれば、つぎのステートメントの方が論理的には優れています。サブクラスのコンストラクタのprototypeプロパティ自体を上書きすることがなく、スーパークラスも呼出されないからです。

Subclass.prototype.__proto__ = Superclass.prototype;

ところが、「ActionScriptコーディングガイド」(PDF)は、「この方法はMacromedia Flash Player 6ではサポートされなくなり、勧められません」と、明確に否定します。実際上も、このObject.__proto__プロパティによる継承(いわゆる「__proto__継承」)は、super演算子でスーパークラスを呼出そうとしたときに問題が生じます。したがって、ActionScript 1.0では、サブクラスのコンストラクタ関数のprototypeプロパティに、スーパークラスのインスタンスを生成して設定する、前述の継承(いわゆる「new継承」)が推奨されます。

2. ActionScript 2.0の継承
ActionScript 2.0は、クラスベース[*4]のプログラミングスタイルを採用しました。クラスは、クラスと同名の外部ActionScriptファイル(asファイル)に記述します。classsキーワードでクラス名を宣言し、そのブロック({})内にプロパティやメソッドを定義します。スーパークラスを継承するには、クラス名に続けて、extendsキーワードによりその指定を行います(詳しくは、「クラスの作成と使用」をご参照ください)。

class Subclass extends Superclass {
   // サブクラスのメソッドとプロパティを定義
}

もっとも、SWFに書出されるバイトコード(Flash Player向けの中間言語)は、ActionScript 1.0が使用するものと基本的に違いがありません(『FLASH OOP − ActionScriptによるオブジェクト指向プログラミング』p.025「ActionScript 2.0 − コンパイル時実装」)。つまり、ActionScript 2.0のクラスの処理も、内部的にはプロトタイプベース[*4]で行われていることになります。

[*4] クラスベースおよびプロトタイプベース(インスタンスベース)の意味については、Wikipedia「オブジェクト指向プログラミング」の「クラス」の項をお読みください。また他に、Starry Night「JavaScript講座」「クラスベースとプロトタイプベース」があります。

実際、「Macromedia Flash (SWF) File Format Specification Version 7」(File Format Specification License Agreementからダウンロード)p.90によれば、ActionScript 2.0のextendsキーワードは、ActionScript 1.0のつぎのスクリプトと同じ扱いになります。

Subclass.prototype.__proto__ = Superclass.prototype;
Subclass.prototype.__constructor__ = Superclass;

これは、Flash Player 6ではサポートしないとされたObject.__proto__プロパティによる継承(「__proto__継承」)が、ActionScript 2.0を使用したFlash Player 7のSWFに採用されたことを意味します。なお、Object.__constructor__は、ドキュメントには記載されていないプロパティです[*5]。

[*5] Object.__proto__およびObject.__constructor__プロパティを使った継承については、「__proto__による継承でsuperを使う」をご参照ください。

3. ActionScript 2.0の継承をFlash Player 6で書出した場合
ActionScript 2.0を使った場合でも、Flash Player 6で書出すことができます(図001)。これは、書出されるバイトコードが、基本的にActionScript 1.0と共通であることにより実現された機能でしょう。しかし、ActionScript 2.0の継承は、Flash Player 7と6とでは、バイトコードが異なるようです。

図001■[パブリッシュ設定]ダイアログの[Flash]タブでPlayerとActionScriptのバージョンを設定

Flash Player 6を選択した場合もActionScript 2.0の使用が可能

サブクラスのコンストラクタ関数から、super演算子でスーパークラスのコンストラクタに引数を渡して呼出す例を見てみましょう(スクリプト002)[*6]。

スクリプト002■ActionScript 2.0でサブクラスからスーパークラスに初期設定値を渡す

class Superclass {
   var prop:Object;
   function Superclass(prop:Object) {
     trace("Superclass is initialized with "+prop);   // 確認用
     this.prop = prop;
   }
}

class Subclass extends Superclass {
   function Subclass(prop:Object) {
     super(prop);   // スーパークラスに初期設定値を引数で渡す
     trace("Subclass is initialized with "+prop);   // 確認用
   }
}


[*6] クラスにコンストラクタが定義されていない場合、空の関数がコンパイル時に自動的に作成されます(「クラスの使用 − シンプルな例」参照)。また、サブクラスのコンストラクタ関数でsuper演算子による呼出しを行っていない場合、コンパイラは自動的にスーパークラスのコンストラクタへの呼出しを生成します(「クラスの作成と使用」参照)。

サブクラスのインスタンスを生成すると、サブクラスのコンストラクタ関数からスーパークラスが呼出されて、引数が渡されますので、結果はつぎのようになります。

// フレームアクション: テスト用
var obj:Subclass = new Subclass("my property");
// [出力](Flash Player 7書出し)
Superclass is initialized with my property
Subclass is initialized with my property

この書出しをFlash Player 6にすると、[出力]結果がつぎのように変化します。

// // [出力](Flash Player 6書出し)
Superclass is initialized with
Superclass is initialized with my property
Subclass is initialized with my property

trace()ステートメントによる出力が、最初に1行加わっています。スーパークラスが引数なしで呼出されている[*7]ことから、サブクラスのコンストラクタ関数のprototypeプロパティにスーパークラスのインスタンスを生成して設定する、ActionScript 1.0の継承(「new継承」)が行われていると考えられます。ActionScript 2.0のバイトコードが1.0と基本的に同じであっても、書出すFlash Playerのバージョンによって内容の異なることがある点には注意が必要でしょう。

[*7] Flash Player 6では、未定義値undefinedをストリングとして扱うと空文字列""に変換されます。Flash Player 7とは異なり、"undefiend"というストリングにはなりません(「ECMA-262準拠」参照)。引数のみを単独でtrace()ステートメントに渡して出力すれば、undefiendと表示されて、値が渡されていないことを確認できます。

_____

作成者: 野中文雄
作成日: 2005年4月10日


Copyright © 2001-2006 Fumio Nonaka.  All rights reserved.