Written 7/7/03
JScript.NET
クラス
JScriptにはオブジェクト指向っぽい言語機能として
ユーザ定義オブジェクトというものがありましたが、
JScript.NETではちゃんとしたクラスが導入されました。
このページでは基本的な機能を紹介します。
ここでは分数クラスを作りますが、
参考までに以前に作った旧分数オブジェクトを紹介しておきます。
分数オブジェクト
見比べてください。
■クラスの定義
分数を扱いやすくするためにFractionクラスを作ってみました。
この例はオブジェクト指向としては適切ではないかもしれませんが。
fraction1.js
---------------------------------------------------------
class Fraction {
private var a : long;
private var b : long;
function Fraction() { a = 0; b = 1; }
function Fraction(a : long) { this.a = a; b = 1; }
function Fraction(a : long, b : long) {
this.a = a; this.b = b;
this.normalize();
}
private function normalize() { //約分
...
}
function ToString() : String {
...
}
...
}
var a : Fraction = new Fraction(2, 6);
print(a);
クラスを作るときは、
class Fraction {
...
}
のようにして、クラス名を指定して、中に定義を書いていきます。
そうすると、下から2番目にあるように、
組み込みオブジェクトと同じように使えます。
var a : Fraction = new Fraction(2, 6);
これは変数aを、分子2、分母6の分数オブジェクトとして初期化しています。
■プロパティ
プロパティは普通に
varを使って定義します。
private var a : long;
private var b : long;
ここではaが分子、bが分母を表しています。
頭に
privateという修飾子がついているのは、
外から直接この値にアクセスできないようにするためです。
var a : Fraction = new Fraction(2, 6);
a.b = 2; //コンパイルエラー
代わりに
publicをつける、
または何もつけないと外からアクセスできます。
なぜこんなことをしたいかというと、
分母と分子は常に約分されているという前提で色々な計算をしたいからです。
例えば、1/3で分子を勝手に3にしたら3/3になってしまいます。
なんにせよ、
基本的には
privateにしておいた方がよいようです。
ただ、外から見るぐらいはいいだろうということで、
次のようなステートメントが用意されています。
class Fraction {
...
function get Bunsi() { return a; }
...
}
こうしておくと、次のようにアクセスできます。
var a : Fraction = new Fraction(2, 6); // 1/3
print(a.Bunsi); //1
これとセットで次のように
function setを定義すると
プロパティの変更もできます。
class Fraction {
...
function get Bunsi() : long { return a; }
function set Bunsi(a : long) {
this.a = a;
normalize(); //約分
}
...
}
var a : Fraction = new Fraction(2, 6);
a.Bunsi = 3;
print(a); //1
function getと
function set
は対になっていることに注意しましょう。
function get Bunsi() : long { ... }
function set Bunsi(a : long) { ... }
こうしておけば1/3の分子に3を代入しても1/1になります
(ちょっと
Dateオブジェクトに似ている?)。
しかし、このクラスではsetは使わないことにします。
■コンストラクタ
オブジェクトを生成するための関数です。
Fractionクラスでは引数によって3つのコンストラクタを用意しています。
class Fraction {
...
function Fraction() { a = 0; b = 1; }
function Fraction(a : long) { this.a = a; b = 1; }
function Fraction(a : long, b : long) {
this.a = a; this.b = b;
this.normalize();
}
...
}
実際にオブジェクトを生成するには、
var f : Fraction;
f = new Fraction(1, 3);
などとします。
上の例では引数の整合性から3番目のコンストラクタが実行されます。
■メソッド
メソッドは普通に
functionを使って定義すればよいです。
class Fraction {
...
private function normalize() {
...
}
function ToString() : String {
if(b == 1)
return a.ToString();
else
return a + "/" + b;
}
...
}
privateが頭についていると、
プロパティと同じようにクラス内でしか使えません。
publicがついている、
またはどちらもついていなければ外から使えます。
static function op_Addition(a : Fraction, b : Fraction) : Fraction {
return new Fraction(a.a * b.b + a.b * b.a, a.b * b.b);
}
このように頭に
staticがついているのは、
インスタンスがいらないということです。
すなわち次のように使います。
var a : Fraction = new Fraction(1, 3);
var b : Fraction = new Fraction(1, 5);
print(Fraction.op_Addition(a, b));
staticがつかないバージョンと較べてください。
...
function Add(f : Fraction) : Fraction {
return new Fraction(a * f.b + b * f.a, b * f.b);
}
...
print(a.Add(b));
■演算子のオーバーロード
演算子のオーバーロードは、どうやらできないみたいです。
こういうときは代わりにC#で書きましょう。
これを利用すると演算子が使えます。
fraction.cs
------------------------------------------------------------------
public class Fraction {
private long a;
private long b;
public Fraction() { a = 0; b = 1; }
public Fraction(long x) { a = x; b = 1; }
public Fraction(long x, long y) { a = x; b = y; normalize(); }
...
//等値演算子
public static bool operator ==(Fraction f1, Fraction f2) {
return f1.a == f2.a && f1.b == f2.b;
}
...
}
JScript.NETとあんまり変わらないように書けるので難しくないでしょう。
このクラスはなるべくオーバーフローしないように作っています。
それでもまだかなり甘いのですが。
そのうち修正すると思います。
これを次のようにコマンドラインからコンパイルしてDLLを作ります。
>csc /target:library fraction.cs
fraction.dllというファイルができていることを確認しましょう。
fraction_test.js
------------------------------------------------------------------
var f1 = new Fraction(1, 3);
var f2 = new Fraction(2, 6);
print(f1 == f2); //true
これを次のようにコンパイルします。
>jsc /reference:fraction.dll fraction_test.js
このようにするとfraction.dllを利用できて、Fractionクラスが使えます。
実は、VB.NETはこのようにしても演算子が使えないので、
JScript.NETはかなりましです。