Platform: All
Version: MX 2004 and above
問題
ActionScript 2.0で確認された問題です。以下のクラス定義(スクリプト001)が、コンパイルエラーになります。
**エラー** 行 11:myTarget' という名前のプロパティはありません。
this.myTarget.testVar=this.myVar;
ActionScript エラー数 :1 報告済みエラー :1
|
スクリプト001■メソッドをLoadVarsインスタンスのコールバック関数に定義
// ActionScript 2.0クラス定義ファイル: Test.as
class Test {
var my_lv:LoadVars;
var testVar:String = "default";
function Test(file_str:String) {
my_lv = new LoadVars();
my_lv.myTarget = this;
my_lv.onLoad = myOnLoad;
my_lv.load(file_str);
}
function myOnLoad() {
this.myTarget.testVar = this.myVar;
}
}
|
確かに、メソッドmyOnLoad()のステートメントには、クラスに宣言されていないプロパティが存在します。左辺のmyTargetおよび右辺のmyVarです[*1]。しかし、myOnLoad()メソッドは、コンストラクタ内でLoadVarsインスタンスmy_lvのLoadVars.onLoadイベントハンドラメソッドに、コールバック関数として設定されています。
したがって、コールバック関数のブロック{}内では、thisがLoadVarsインスタンスmy_lvを参照します。my_lvには、コンストラクタ内でプロパティmyTargetが設定され、また外部テキストファイルから変数myVarがロードされるはずです。これらを、クラスTestのインスタンスプロパティとして定義すべき理由は見当たりません。
[*1] 上記のコンパイルエラーに、myVarは含まれていません。しかし、myTargetのエラーを解消すると、myVarについての警告が現れます。
|
原因
myOnLoad()メソッドは、実際の呼出し方はともかく、形式上はインスタンスメソッドとして定義されています。すなわち、Testインスタンスを参照して、メソッドが呼出される可能性は存在することになります。ActionScript 2.0の型指定はコンパイル時のみの実装ですので、ランタイムの実際の呼出しまでは評価が及ばず、形式的なエラーチェックにとどまっているようです。
したがって、クラスのインスタンスを参照してメソッドを呼出した場合があくまで基準となり、アクセスされるプロパティにはクラスで宣言しておくことが求められるものと推測されます。
対処法
対処の方法としては、3つ考えられます。
[1] インスタンスプロパティとして宣言する
エラーの警告にしたがって、クラスにインスタンスプロパティとして宣言することが考えられます(スクリプト002)。もちろん、クラスのインスタンス自身が、そのプロパティを必要とすることはありません。ですから、プロパティを宣言したからといって、とくに動作に問題を生じることもないでしょう。
スクリプト002■エラーを避けるためインスタンスプロパティとしてクラスに定義
// ActionScript 2.0クラス定義ファイル: Test.as
class Test {
var my_lv:LoadVars;
var testVar:String = "default";
var myTarget:Object;
var myVar:String;
function Test(file_str:String) {
my_lv = new LoadVars();
my_lv.myTarget = this;
my_lv.onLoad = myOnLoad;
my_lv.load(file_str);
}
function myOnLoad() {
this.myTarget.testVar = this.myVar;
}
}
|
最大の難点は、スクリプトを見た人に、宣言したインスタンスプロパティがクラスのインスタンスに必要であるかのような誤解を与えかねない点です。
[2] 配列アクセス演算子でプロパティにアクセスする
配列アクセス演算子[]を使ってプロパティにアクセスすると、宣言や型指定のチェックが適用されません。ですから、エラーを発生させるプロパティは、配列アクセス演算子[]で参照すれば、コンパイルが可能になります(スクリプト003)。
スクリプト003■エラー発生させるプロパティは配列アクセス演算子で参照
// ActionScript 2.0クラス定義ファイル: Test.as
class Test {
var my_lv:LoadVars;
var testVar:String = "default";
// var myTarget:Object;
// var myVar:String;
function Test(file_str:String) {
my_lv = new LoadVars();
my_lv.myTarget = this;
my_lv.onLoad = myOnLoad;
my_lv.load(file_str);
}
function myOnLoad() {
// this.myTarget.testVar = this.myVar;
this["myTarget"].testVar = this["myVar"];
}
}
|
しかし逆に言えば、配列アクセス演算子を使うということは、厳密な型指定というActionScriptの特長を捨て去る結果になります。したがって、その使用は必要最小限にとどめるべきでしょう。
[3] Delegateクラスの使用
今回のスクリプトの例では、Delegateクラスを利用すれば、インスタンスに不要のプロパティ宣言をしたり、配列アクセス演算子[]を使用せずにメソッドを定義することができます(スクリプト004)。コールバック関数に設定したメソッド内であっても、スコープつまりthis参照をクラスのインスタンスに指定することができるからです。
スクリプト004■Delegateクラスを使ってコールバック関数を指定
import mx.utils.Delegate;
class Test {
var my_lv:LoadVars;
var testVar:String = "default";
// var myTarget:Object;
// var myVar:String;
function Test(file_str:String) {
my_lv = new LoadVars();
my_lv.myTarget = this;
// my_lv.onLoad = myOnLoad;
my_lv.onLoad = Delegate.create(this, myOnLoad);
my_lv.load(file_str);
}
function myOnLoad() {
// this.myTarget.testVar = this.myVar;
// this["myTarget"].testVar = this["myVar"];
testVar = my_lv.myVar;
}
} |
ActionScript 2.0のスタンダードにしたがいつつ、問題を回避できることは利点です。ただ、スクリプトの構造によっては、Delegateクラスでは解決できない場合もありうるでしょう。
_____
作成者: 野中文雄
作成日: 2005年8月9日