|
|
連載
ASP→ASP.NET移行テクニック
第3回 ASP/ASP.NETを支える周辺技術の移行
山田 祥寛
2004/06/19 |
|
|
●変数をあらかじめ宣言しなければならない
旧来のJScriptでは、変数の宣言が必ずしも必要なかった。つまり、旧来のVBにおける問題点(デバッグの困難化)が、JScriptにおいても起こり得たということだ。
そこで、高速モードのJScript .NET(以降、単に「JScript .NET」。特記しない限りは「高速モード」とする)においては、変数の明示的な宣言が必須となった。JScript .NETにおいては、以下のような構文で変数を宣言することができる。
var 変数名 [: データ型] [=初期値], [変数名 [: データ型] [=初期値],...];
例:var author : String = "Yoshihiro Yamada";
|
|
JScript .NETにおける変数宣言の構文 |
JScript .NETにおいてデータ型の宣言は必須ではないが、型宣言されていないコードは実行時に型の割り当てが行われるため、低速なだけでなく、時として型の誤認識などから思わぬエラーの原因となることがある。特別な理由がない限り、型宣言を行う癖を付けるようにしておきたい。
なお、varステートメントでは複数の変数をまとめて宣言することが可能であるが、この際、型宣言は個々の変数について明示する必要がある点に注意してほしい(この点は、VB.NETとは異なるので、注意が必要だ)。例えば、以下のコードでは変数yのみがString型であると見なされ、変数xの型は特定されない(正確にはすべての型の基底型であるObject型が割り当てられる)。
|
複数の変数をまとめて宣言するコード(先頭にしか型宣言がない場合) |
変数yのみがString型であると見なされ、変数xの型は特定されない。 |
もしも変数xにもString型を割り当てたいならば、以下のように記述しなければならない。
var x : String, y : String; |
|
複数の変数をまとめて宣言するコード(個々の型宣言を明示した場合) |
変数xも変数yもString型であると見なされる。 |
●関数は定数であると見なされる
旧来のJScriptでは、functionステートメントを使って宣言された関数は、Function型の変数として処理された。つまり、以下のようなコードも実現可能であるということだ。この場合、関数dataは、最後の行で文字列型の変数dataによって置き換えられる。
function data() {
Response.Write("OK");
}
data = "sample";
|
|
旧来のJScriptでの関数の取り扱いを示すコード |
旧来のJScriptでは、関数はFunction型の変数として扱われる。この例では、関数dataは、最後の行で文字列型の変数dataによって置き換えられる。 |
しかし、JScript .NETでは関数は定数であると見なされる。つまり、上のようなコードは不可である。関数をほかのスカラー値で置き換えたり、関数として再定義したりすることはできない。
もしも途中で関数の再定義が必要である場合には、初回の定義時に明示的にFunctionクラスのインスタンスを生成する必要がある。
var calculate : Function = new Function("x", "y", "return(x*y)"); |
|
JScript .NETで関数を再定義するために事前に必要なコード |
この例のように、初回の定義時に明示的にFunctionクラスのインスタンスを生成しておくと、途中で関数を再定義することができるようになる。 |
●argumentsオブジェクトは利用できない
argumentsオブジェクトは、実行中の関数に関するパラメータを保持するためのオブジェクトだ。旧来のJScriptではargumentsオブジェクトを利用することで、可変長パラメータの関数を利用できた。
例えば、以下のsum関数はパラメータとして渡された数値をすべて合算した結果を戻り値として返す。
function sum(){
intSum = 0;
for (i = 0; i < arguments.length; i++){
intSum += arguments[i];
}
return intSum;
}
Response.Write(sum(1, 5, 10));
|
|
旧来のJScriptでのargumentsオブジェクトを利用したコード |
sum関数はパラメータとして渡された数値をすべて合算し結果を戻り値として返す。 |
しかし、JScript .NETではargumentsオブジェクトのサポートが廃止され、代わりにパラメータ配列が提供された。上記の例をJScript .NET対応に書き直してみると、以下のようになる。パラメータ配列は「...<配列名> : <データ型>」の形式で表すことができる。
function sum(... aryNum : int[]) : int {
var intSum : int =0;
for(var num in aryNum) {
intSum+=aryNum[num];
}
return intSum;
}
Response.Write(sum(1,5,10));
|
|
JScript .NETでのパラメータ配列を利用したコード |
上記の「旧来のJScriptでのargumentsオブジェクトを利用したコード」をJScript .NETに対応させたコード。argumentsオブジェクトの代わりにパラメータ配列を使用している。パラメータ配列は「... <配列名> : <データ型>」の形式で表すことができる。 |
●組み込みオブジェクトへの拡張プロパティは使用できない
旧来のJScriptでは、StringやArrayなどの組み込みオブジェクトに対して、動的にプロパティやメソッドを追加・変更することができた。例えば、以下のコードはStringオブジェクトに対して「末尾の1文字を削除する」chopメソッドを追加するものである。
function addMethod(){
return this.substring(0, this.length - 1);
}
String.prototype.chop = addMethod;
Response.Write("abcde".chop());
|
|
旧来のJScriptでの組み込みオブジェクトへ動的にメソッドを追加するコード |
旧来のJScriptでは、StringやArrayなどの組み込みオブジェクトに対して、動的にプロパティやメソッドを追加・変更することができた。 |
しかし、JScript .NETではもはや組み込みオブジェクトへの拡張プロパティ(expando)はサポートしない。もしもexpandoに依存するコードを記述している場合には、グローバル・スコープの関数を別に用意したうえで、オブジェクトを関数のパラメータとして引き渡すよう、コードを改変する必要がある。
function chop(str1 : String) : String {
return str1.substring(0, str1.length-1);
}
Response.Write(chop("abcde"));
|
|
上記の組み込みオブジェクトへのメソッド追加コードをJScript .NET対応させたコード |
JScript .NETでは、組み込みオブジェクトへ動的にプロパティやメソッドを追加・変更できず、拡張プロパティ(expando)もサポートされない。この例では、組み込みオブジェクトにメソッドを追加する代わりに、関数のパラメータとしてオブジェクトを取得して、戻り値として結果を返している。 |
●読み取り専用のプロパティ(フィールド)に対する値設定を許さない
旧来のJScriptにおいては、読み取り専用のプロパティに対して値の設定を行ったとしてもエラー通知は行われなかった。例えば、以下のコードは文字列長(lengthプロパティ)に対して値を設定するもので、コード的にはまったく意味がない。
"abcde".length = 6;
Response.Write("abcde".length);
|
|
旧来のJScriptで読み取り専用プロパティに値を設定したコード |
旧来のJScriptにおいては、読み取り専用のプロパティに対して値の設定を行ったとしてもエラー通知は行われなかった。 |
上記コードを実行した結果、lengthプロパティへの代入は無視され、lengthプロパティは何事もなかったかのように正しい結果である5を返す。しかし、これはまったく無意味な仕様であるのみならず、エラー原因を隠ぺいするもととなるものだ。JScript .NETではこの仕様が改められ、コンパイル・エラーを出力するようになった。
●evalメソッド内の識別子は外部スコープからアクセスできない
evalメソッドは、パラメータとして渡されたコードを動的に(実行時に)評価し、実行する。旧来のJScriptでは、evalメソッド内で定義された変数や関数はローカル、またはグローバルなスコープで利用することができた。つまり、以下のようなコードは「可」である。
eval("var str1='text';");
Response.Write(str1);
|
|
旧来のJScriptにおけるevalメソッド |
旧来のJScriptでは、evalメソッド内で定義された変数や関数はローカル、またはグローバルなスコープで利用することができた。 |
しかし、JScript .NETにおけるevalメソッドは、あくまでその場限りのものとなる。つまり、evalメソッド内で定義された変数や関数は直ちに破棄され、外部のスコープからはアクセスすることができない。ただし、evalメソッド内から外部スコープの変数にアクセスすることはできるので、以下のようなコードも可能ではある。
var str1 : String;
eval("str1 = 'text';");
Response.Write(str1);
|
|
JScript .NETにおけるevalメソッド |
JScript .NETでは、evalメソッド内で定義された変数や関数は直ちに破棄され、外部のスコープからはアクセスすることができない。ただし、この例のように、evalメソッド内から外部スコープの変数にアクセスすることはできる。 |
ただ、evalメソッドによるコードの動的実行は極めて低速であるので、このような改変をするよりもevalメソッドを使用しないようにコードを書き直すことを強くお勧めする。
それでは次に、COMコンポーネントの移行について解説しよう。