ユーザ定義オブジェクト

はじめに

JavaScriptの高度な書き方,JavaScriptのユーザ定義オブジェクトの作成方法について記します.

ユーザ定義オブジェクトとは,その名の通りユーザで定義するオブジェクトです.JavaScriptには組み込みオブジェクトとして,Stringオブジェクト, Mathオブジェクト,RegExpオブジェクトなど数々の有用なオブジェクトが用意されています.ユーザ定義オブジェクトとは,ユーザで定義したこのようなオブジェクトのことをいいます.

JavaScriptはC/Pascal言語のような手続き型でプログラミングできますし,C++/Java言語のようにオブジェクト指向型のプログラミングをすることもできます.JavaScriptは本格的なオブジェクト指向型言語とは言えませんが,一つ大きな機能として「フィールドとメソッドを一つのまとまりとして定義するオブジェクトの抽象化」を備えています.このような特徴を利用して,有用なユーザ定義オブジェクトを作成していきましょう.

尚,タイトルは「ユーザ定義“オブジェクト”」と書いていますが,厳密にはこれは違う意味で使われるので,ここでは「ユーザ定義“クラス”」または単に“クラス”と記述することにします.

オブジェクト指向とは?

私から言及すると実に危ういので(^^);ある書籍から一部引用.

オブジェクトとはその名の通り「物」のことです.現実世界には色々な物があります.例えば,はさみ,鉛筆,本などは「物」です.そういった物には「状態」や「ふるまい」があります.例えば,鉛筆であれば,「状態」は線の色,色の濃さ,線の太さなどで,「ふるまい」は線が引けるなどです.こういった物の「状態」や「ふるまい」をプログラムに持ち込んだものがオブジェクト指向です.

実際のプログラムでは「状態」を変数で表し,「ふるまい」を関数で表すことになります.そしてこれらの変数 / 関数のことをJavaScriptではプロパティと呼んだりします.

オブジェクトとは? / クラスとは?

オブジェクトとクラスは意味が異なります.例えば「手に持っている鉛筆」は「オブジェクト(物)」ですが,「鉛筆と考えられている物」はオブジェクトではなく,「クラス」ということになります.つまり“クラス”は概念的な雛型であり,それから実際に生成される物が“オブジェクト”ということになります.

プログラムでは,クラスは「状態」や「ふるまい」を定義した箱であり,オブジェクトは実際に動作するものです.

ここで注意ですが,オブジェクトという言葉は非常に曖昧な言葉で広い範囲でなんでもかんでもオブジェクトと呼ぶことができます.そう言っても問題がないためです.ですので私はクラスから生成されたものをJava言語に習い,インスタンスと呼ぶことにします.

例えば,JavaScriptには日付を定義しているDateオブジェクト(=Dateクラス)がありますが,

var date = new Date();

Dateはクラスであり,dateDateクラスのインスタンスということになります.

何やら難しいですね.これらを別に知っておかなくてもプログラムは書けちゃいますので,オブジェクト指向については他書籍等を参考にして下さい.

オブジェクト指向の利点

プログラムにはさまざまな部品があり,それらが個々の機能を持つことでプログラム全体としての機能を果たすことになります.

部品をクラス化することにより,ある範囲に閉じるべきデータ(変数)や機能(関数)が一まとめにされますので,独立性が高まります.独立性の高い部品は保守性が高くなります.

またデータや機能が一まとめになったことで,部品を抽象化しやすくなります.抽象度の高い部品は,汎用性が高くなります.

独立性の高い部品,汎用性の高い部品は,再利用性が高くなります.

これを見てなるほどと思う人なんて一人もいないでしょうf^^;.実際には長い間オブジェクト指向プログラミングを行ってみたり,デザインパターンを理解して初めて利点が分かるものかも知れません.

コンストラクタの定義(プログラムを書いてみましょう)

前置きが長くなりました.では,実際にプログラムを書いてみましょう.

クラス化にはコンストラクタ関数を使用します.コンストラクタ関数といっても,特にJavaScriptに特別な構文があるわけでもなく,普通の関数と同じように書くことが出来ます.

ここでは「長方形」を表すクラス,Rectangleクラスを定義することにします.長方形を定義するために必要な情報は幅(width)と高さ(height)です.

// 長方形クラスのコンストラクタ関数の定義
function Rectangle(width, height) {
    this.width = width; // 長方形の幅
    this.height = height; // 長方形の高さ
}

これでRectangleクラスのコンストラクタ関数は定義できました.とんでもなく,あっけないです.Rectangleクラスは長方形の幅/高さを表すwidth/heightをプロパティとして保持しています.

thisキーワードでプロパティを初期化していることに注意して下さい.また,コンストラクタはプロパティを初期化するだけです.引数付きreturn文を使用してはいけません

では,実際にRectangleクラスのインスタンスを生成してみましょう.

var r0 = new Rectangle(2, 1);
var r1 = new Rectangle(4, 2);

これでr0およびr1は,Rectangleクラスのインスタンスになりました.このようにインスタンスを生成するには,new演算子を使うことになります.

これからプロパティwidth, heightを取り出すには次のようにします.

alert(r0.width);  // 結果は 2
alert(r0.height); // 結果は 1
alert(r1.width);  // 結果は 4
alert(r1.height); // 結果は 2

ドット(.)演算子を使用して,その後ろにプロパティ名を指定することになります.簡単ですね.

メソッドの定義

インスタンスを介して呼び出す関数のことをメソッドと呼びます.

追加するメソッドは長方形の面積を取得するものにしましょう(面積=幅×高さ).先ほどのプログラムをそのまま引用して書いてみます.

// 長方形クラスのコンストラクタ関数の定義
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// メソッドの定義(この関数がメソッドになる).
// 内部でthisキーワードを使用していることに注意.
function getArea__Rectangle() {
    return this.width * this.height;
}

// インスタンス生成
var r0 = new Rectangle(3, 2);
var r1 = new Rectangle(8, 6);

// メソッドの追加.
// r0.getAreaのgetAreaがメソッド名になる.
r0.getArea = getArea__Rectangle;

// メソッドの呼び出し
alert(r0.getArea()); // 結果は 3 * 2 で 6

このように,メソッドを追加するときはドット(.)演算子の後ろでメソッド名を指定して,= のあとに実際に処理する関数(この場合,getArea__Rectangle)を指定します.簡単ですよね.

ですが,これには問題点があります.それは,このメソッドを使えるのが r0 のみであることです.例えば,r1.getArea()とは書けません.

普通はこういったメソッドは共有させ,全インスタンスで使用したいものです.r1.getArea = getArea__Rectangle; r2.getArea = getArea__Rectangle;...と力技で書けなくもないですが,もっとシンプルで効率的な方法があります.次項ではその共有方法について説明します.

メソッドの共有

上記で説明したメソッドは一つのインスタンス(r0)でしか使用できないものでした.では,メソッドを全インスタンスで共有して使用するにはどうすれば良いのでしょうか?

但し,widthやheightといったインスタンス固有のものは共有せず,メソッドだけを共有したいということです.

それには,Function#prototypeプロパティを使用します(prototypeプロパティについての説明については,かなり長くなりますのでここでは説明しません.というか私もよく分かっていないので,説明できないだけです.というのは半分冗談な話ですが,prototypeプロパティは以下以外の用途で使用することは稀です.この用法だけ覚えておいて問題ありません.).

とりあえず,プログラムを見てみましょう.

// 長方形クラスのコンストラクタ関数の定義
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// メソッドの定義.
function getArea__Rectangle() {
    return this.width * this.height;
}

// メソッドの追加.
Rectangle.prototype.getArea = getArea__Rectangle;

// インスタンス生成
var r0 = new Rectangle(3, 2);
var r1 = new Rectangle(8, 6);

// メソッドの呼び出し
alert(r0.getArea()); // 結果は 3 * 2 で  6
alert(r1.getArea()); // 結果は 8 * 6 で 48

prototypeで追加されたメソッドは全インスタンスで共有(に継承)されます.

尚,上記プログラムでは定義と追加を分けて記述していますが,定義と追加を分けて記述することの利点は古いブラウザに対する互換性だけです.無名関数を使用すると以下のようにシンプルに記述できます.

// 長方形クラスのコンストラクタ関数の定義
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// メソッドの定義(と追加).
Rectangle.prototype.getArea = function() {
    return this.width * this.height;
};

// インスタンス生成
var r0 = new Rectangle(3, 2);
var r1 = new Rectangle(8, 6);

// メソッドの呼び出し
alert(r0.getArea()); // 結果は 3 * 2 で  6
alert(r1.getArea()); // 結果は 8 * 6 で 48

これでユーザ定義オブジェクトの基本は終了です.簡単でしたか?.次項ではクラス化したときの注意点について書いています.

よくある間違い

クラス化して最初に間違え,悩むことは恐らくココに書いていることです.重要なので必ず,読んでください.アラートダイアログに何が表示されるか考えながら読んでみて下さい.

例えば以下のプログラムです.

var r0 = new Rectangle(3, 2);
var r1 = new Rectangle(4, 6);

alert(r0 == r1);

これは,予想通り false が表示されます.では,次はどうでしょう.

var r0 = new Rectangle(1, 1);
var r1 = new Rectangle(1, 1);

alert(r0 == r1);

true が表示されると思いますか?.それは間違いです.やっぱり,false が表示されます.これは中身が同じでも参照している場所が違うためです.では,次はどうだと思いますか?

var r0 = new Rectangle(1, 1);
var r1 = r0;

alert(r0 == r1);

これは true が表示されます.参照している場所が一緒のためです.これらはポインタ(or 参照)と呼ばれる概念がそういう結果を生みます(ここでは説明しません).

これと関連して次のプログラムを見てみましょう.

var r0 = new Rectangle(4, 3);
var r1 = r0;

r0.width = 5;

alert(r1.width);

答えは 4 ではなく,5 です.つまり,r1 = r0 とした時点で r0 と r1 は同じところを参照し,このままではずっと連動してふるまうことになります.意図通りに表示したい(4を表示したい)場合は次のように書きます.

var r0 = new Rectangle(4, 3);
var r1 = new Rectangle(r0.width, r0.height);

r0.width = 5;

alert(r1.width);

こうしておけば,ステータスバーに表示されるのは 4 です.newで新たなインスタンスを作成することが重要です.

最後にもう少し踏み込んだ,誤解しやすいプログラムを示します.swap関数です.

function swap(a, b) {
    var temp = a;
    a = b;
    b = temp;
}

var r0 = new Rectangle(0, 0);
var r1 = new Rectangle(1, 1);

alert(r0.width); // 結果は 0

swap(r0, r1);

alert(r0.width); // 結果は ?

残念ながらこのプログラムを実行してもr0とr1は入れ替わりません.JavaScriptの関数の参照渡しは,参照そのものではなく,参照しているアドレスの値を渡しているからです.かといって関数の引数に渡すときに,インスタンスそのもののコピーが作成されるわけではありませんので,以下のプログラムは意図した通りに動作します.

function changeValue(a, b) {
    a.width = 10;

    var temp = b;
    temp.width = 100;
}

var r0 = new Rectangle(0, 0);
var r1 = new Rectangle(1, 1);

alert(r0.width); // 結果は  0
alert(r1.width); // 結果は  1

changeValue(r0, r1);

alert(r0.width); // 結果は 10
alert(r1.width); // 結果は100

これらが参照型(object/array/function)の特徴ですが分かりましたでしょうか?.

Javaの場合は同じ挙動を示すので問題ないですが,C++から飛び込んだ人は戸惑うかもしれません.JavaScriptでインスタンスを扱う場合,常に参照渡し(参照しているアドレスの値渡し.つまり本質的には値渡し)であることを念頭に置いてプログラミングして下さい.

次項からは,これだけでは物足りないという人にもう一歩進んだオブジェクト指向について説明します.

言葉の定義

一歩進む前に言葉の定義をはっきりしておきましょう.

JavaScriptのオブジェクト指向的側面が注目されていないためか,曖昧な言葉が多いように思われます.恐縮ながら,Java言語で学んだ私なりの言葉の定義を示しておきます.

名称内容・説明
クラス物の状態やふるまいを定義した概念的な雛形.Date, Rectangle...
インスタンスクラスから生成(new)された実際のもの.同義語:(狭義の)オブジェクト.date, r0, r1...
インスタンス変数インスタンスに関連付けされている変数.同義語:インスタンスフィールド.width, height...
インスタンスメソッドインスタンスに関連付けされている関数.getTime, getArea...
クラス変数クラスに関連付けされている変数.同義語:クラスフィールド.Math.PI...
クラスメソッドクラスに関連付けされている関数.Math.floor, String.fromCharCode...
メンバクラスの構成要素全体.クラスはインスタンス変数,インスタンスメソッド,クラス変数,クラスメソッドで構成される.

何もかもプロパティと呼んでいましたがこれだけでも,きちんとしたはずです.次項からはこれらについて説明しますが,インスタンス,インスタンス変数,インスタンスメソッドについてはもう理解できましたよね.

クラス変数 / クラスメソッド

JavaScriptでクラス変数,クラスメソッドを表現してみましょう.これも操作的には簡単です.例としてはRectangleクラスに√2の値を追加することにします.

// クラス変数の定義.
Rectangle.SQRT2 = 1.414;

// クラス変数の参照.
alert(Rectangle.SQRT2); // 結果は 1.414

終わりです(笑).つまり,クラス変数とは,クラスそのものに関連付けされたものですから,その名の通りクラスに変数を追加します.次はクラスメソッドですが,もう分かりましたね.例では二つのRectangleクラスのインスタンスの面積を調べ,大きい方の値を返すメソッドを追加することにします.

// コンストラクタの定義.
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// クラスメソッドの定義.
// 2つのRectangleクラスのインスタンスを引数にとり,大きいほうの面積を返す.
Rectangle.getAreaMax = function(p, q) {
    return Math.max(p.getArea(), q.getArea());
};

// インスタンスメソッドの定義.
Rectangle.prototype.getArea = function() {
    return this.width * this.height;
};

// インスタンス生成.
var r0 = new Rectangle(3, 2);
var r1 = new Rectangle(6, 4);

// クラスメソッドの呼び出し.
alert(Rectangle.getAreaMax(r0, r1)); // 結果は 24

クラスメソッドの呼び出しは,クラス名のあとにメソッド名を書けばよいだけです.

クラス変数やクラスメソッドの作成は,全インスタンスを統括して扱うなど,これを利用すると実に設計性の高いすっきりした綺麗なプログラムを作成できるようになります.

クラスの継承

// 基底クラスのコンストラクタ.
function SuperClass() {
    ...
}

// 派生クラスのコンストラクタ.
function SubClass() {
    ...
}

SubClass.prototype = new SuperClass(); // 継承.

prototypeって便利ですね(笑).このように書くことで,SubClassはSuperClassを継承したクラスになります.但し,Java言語などとは違いクラスメンバは継承されませんので注意して下さい.

継承を実現する方法はもう一つあって,私はこちらがお勧めです.何が違うのかは自分で考えて下さい f(^^;

// 継承メソッド(汎用).
Function.prototype.inherit = function(super_class) {
    function Temp() {}
    Temp.prototype = super_class.prototype;
    return this.prototype = new Temp;
};

//--------------------------------------------------//

// 基底クラスのコンストラクタ.
function SuperClass() {
    ...
}

// 派生クラスのコンストラクタ.
function SubClass() {
    ...
}

SubClass.inherit(SuperClass); // 継承.

尚,派生クラスのコンストラクタにおいて基底クラスのコンストラクタを呼び出したい(Javaの予約語superを使用したい)場合,以下のように書くことができます.

// 基底クラスのコンストラクタ.
function SuperClass(p, q) {
    this.p = p;
    this.q = q;
}

// 派生クラスのコンストラクタ.
function SubClass(p, q, r) {
    this.constructor(p, q); // Java言語の super(p, q); と等価.
    this.r = r;
}

SubClass.inherit(SuperClass); // 継承.

toStringメソッド / valueOfメソッド

toString/valueOfをインスタンスメソッドとしてクラスに定義することで,クラスのインスタンスに特別な機能を持たせることができます.

先ず,toStringメソッドから説明します.例にはRectangleクラスを使用します.

// コンストラクタの定義.
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// toStringメソッドの定義.
Rectangle.prototype.toString = function() {
    return "長方形 : " + this.width + "×" + this.height;
};

// インスタンス生成.
var r0 = new Rectangle(3, 2);

// 出力.
alert(r0); // 結果は???

これを実行すると何がステータスバーに表示されると思いますか? 答えは "object" でも,"undefined" でもなく,"長方形 : 3×2" です.

toStringメソッドはそのクラスのインスタンスが文字列型で参照されたときに自動的に呼び出されます.toStringを定義しておくことはプログラムの作法的にも重要なことです.デバッグ作業が断然楽になります.ユーザ定義クラスを作成したときは,toStringメソッドを定義しておくことを勧めます.

次に valueOfメソッドですが,toStringが文字列型であったのに対し,valueOfメソッドは文字列型以外の基本型(主に数値型)で参照されたときに呼び出されます.例として,ここではあまり実用的ではないですが,面積を返すようにします.

// コンストラクタの定義.
function Rectangle(width, height) {
    this.width = width;   // 長方形の幅
    this.height = height; // 長方形の高さ
}

// valueOfメソッドの定義.
Rectangle.prototype.valueOf = function() {
    return this.width * this.height;
};

// インスタンス生成.
var r0 = new Rectangle(4, 3);

alert(r0 - 0); // 結果は 4 * 3 - 0 で 12

- 0”を付加しているのはこれが数値であることを明示的にするためです.toStringメソッドとvalueOfメソッドのどちらが呼び出されるかは曖昧なときがあります.toSringメソッドを呼び出したいときは "" + r0, valueOfメソッドを呼び出したいときは r0 - 0 とするのが確実です.

さいごに

さいごに恐縮ですが,私なりのクラス化の方法と記述の仕方について書きたいと思います.例にはRectangleクラスを使用します.

ユーザ定義オブジェクトの作成例については JavaScript / DHTML Class Libraryのページがあるので,そちらも参考にして下さい.

// 関数class__ClassName__(Frame frame)のなかで,ClassNameクラスの定義を全て記述します.
// 関数の引数Frame frameは,ClassNameクラスを使用するフレーム(ウィンドウオブジェクト)を指定します.
// 通常はwindowを指定します.

/**
 * Rectangleクラスの定義.
 */
function class__Rectangle__(window) {
    // Rectangleクラスのクラス名称です.
    // このように文字列として保持しておくことで便利なことがあります.
    var className = "Rectangle";

    /**
     * Rectangleクラスのコンストラクタの定義.
     * 
     * Rectangle()
     * width = 1.0, height = 1.0;
     * 
     * Rectangle(Rectangle r)
     * width = r.width, height = r.height;
     * 
     * Rectangle(number w, number h)
     * width = w, height = h;
     * 
     * Rectangle(number n) : おまけ
     * width = n, height = n;
     */
    // 下記FがRectangleクラスを意味します.
    // スコープをwindowにしていることに注意です.
    var F = window[className] = function() {
        var a = arguments;

        switch (a.length) {
            case 0 : default : {
                this.width = this.height = 1.0;
                break;
            }
            case 1 : {
                if (a[0].constructor === F) {
                    this.width  = a[0].width;
                    this.height = a[0].height;
                } else {
                    this.width = this.height = a[0];
                }
                break;
            }
            case 2 : {
                this.width = a[0];
                this.height = a[1];
                break;
            }
        }
    };

    /**
     * Rectangleクラスのプロトタイプオブジェクト.
     */
    var FP = F.prototype;

    // クラス変数の定義.

    F.SQRT2 = 1.414;

    // クラスメソッドの定義.

    /**
     * 複数のインスタンスを引数にとり,最大の面積を返す.
     * getMaxArea(Rectangle r0, Rectangle r1[, Rectangle r2,...])
     * @return number 最大の面積の値.
     */
    F.getMaxArea = function() {
        var a = arguments;
        var n = a.length
        var max_s = a[0].getArea();
        for (var i = 1; i < n; i++) {
            var s = a[i].getArea();
            if (s > max_s)
                max_s = s;
        }
        return max_s;
    };

    /**
     * 複数のインスタンスを引数にとり,最小の面積を返す.
     * getMinArea(Rectangle r0, Rectangle r1[, Rectangle r2,...])
     * @return number 最小の面積の値.
     */
    F.getMinArea = function() {
        var a = arguments;
        var n = a.length
        var min_s = a[0].getArea();
        for (var i = 1; i < n; i++) {
            var s = a[i].getArea();
            if (s < min_s)
                min_s = s;
        }
        return min_s;
    };

    // インスタンスメソッドの定義.

    /**
     * 幅を設定する.
     */
    FP.setWidth = function(width) {
        this.width = width;
    };

    /**
     * 高さを設定する.
     */
    FP.setHeight = function(height) {
        this.height = height;
    };

    /**
     * 幅を取得する.
     */
    FP.getWidth = function() {
        return this.width;
    };

    /**
     * 高さを取得する.
     */
    FP.getHeight = function() {
        return this.height;
    };

    /**
     * 面積を取得する.
     * @param number 面積.
     */
    FP.getArea = function() {
        return this.width * this.height;
    };

    /**
     * 対角線の長さを取得する.
     * L = √(w^2 + h^2)
     * @return number 対角線の長さ.
     */
    FP.getDiagonalLineLength = function() {
        return Math.sqrt(this.width * this.width + this.height * this.height);
    };

    /**
     * スケーリングする.
     * @param number scale スケーリング値.
     */
    FP.scale = function(scale) {
        this.width *= scale;
        this.height *= scale;
    };

    // 下記のようにメソッド定義の中で他のメソッドを使用することもできます.
    /**
     * 幅と高さを半分にする.
     */
    FP.half = function() {
        this.scale(0.5);
    };

    /**
     * 誤差を指定して引数と比較.
     * @param Rectangle r 比較対象.
     * @param number e 誤差.
     * @return boolean 比較対象の幅と高さが指定した誤差内にあるとき真.
     */
    FP.epsilonEquals = function(r, e) {
        var d = this.width - r.width;
        if ((d >= 0.0 ? d : -d) > e)
            return false;
        d = this.height - r.height;
        return (d >= 0.0 ? d : -d) <= e;
    };

    /**
     * 配列型に変換する.
     * 
     * toArray()
     * @return Array 幅と高さを要素に持つ配列.
     * 
     * toArray(Array array);
     * @param Array array 要素(幅と高さ)を納める配列.
     * @return Array 引数の参照.
     */
    FP.toArray = function(array) {
        if (array !== void 0) {
            array[0] = this.width;
            array[1] = this.height;
            return array;
        } else {
            return this.toArray(new Array(2));
        }
    };

    /**
     * 数値型表現を返す.
     * @return number 面積.
     */
    FP.valueOf = function() {
        return this.getArea();
    };

    // toStringメソッドは必ず定義しておきましょう.
    /**
     * 文字列型表現を返す.
     * @return String Rectangleクラスの文字列型表現.
     */
    FP.toString = function() {
        return className + " : " + this.width + " × " + this.height;
    };

    // equalsメソッド(比較メソッド)は可能ならば定義しておきましょう.
    /**
     * 比較する.
     * @param object o 比較対象.
     * @return boolean 引数と幅および高さが等しいとき真.
     */
    FP.equals = function(o) {
        if (o.constructor !== F)
            return false;

        return o.width === this.width && o.height === this.height;
    };

    // cloneメソッド(複製メソッド)は余裕があるなら定義しておきましょう.
    /**
     * 複製する.
     * @return Object 自分自身のコピー.
     */
    FP.clone = function() {
        return new F(this);
    };
} class__Rectangle__(window);
// ↑Rectangleクラスの定義の呼び出し.
// この呼び出しで初めてRectangleクラスを使用することができます.
// Rectangleクラスが使用できるフレーム(ウィンドウ)はここで指定したwindowだけです.

使用例は以下です.

/* インスタンスの生成.*/

var r0 = new Rectangle();
alert(r0); // 結果は "Rectangle : 1 × 1"

var r1 = new Rectangle(8, 6);
alert(r1); // 結果は "Rectangle : 8 × 6"

var r2 = new Rectangle(r1);
alert(r2); // 結果は "Rectangle : 8 × 6"

/* インスタンスメソッドの呼び出し.*/

r2.half();
alert(r2); // 結果は "Rectangle : 4 × 3"

/* クラスメソッドの呼び出し.*/

alert(Rectangle.getMaxArea(r0, r1, r2)); // 結果は48 (= 8 * 6)