Section 2.10 クロージャ

前回まででクラスの重要な機能は一通り見てきたんだけど、 クラス関係でまだ説明してない機能があるから、今回からはその話ね。
…って言っても、今回から2章の終わりまでの内容は、知らなくてもそれなりにちゃんとしたスクリプトは書けるんだけどね。
えっ、そうなの?
じゃあ、別に説明しなくてもいいんじゃ…
まぁそうなんだけど、TJS の特徴的な機能だし、知っとくと便利な場合もあるからね。
ふぅん…そうなんだ。
それで、今回はどんな内容なの?
§1.19 で関数の参照について説明したよね。
えっと、確か変数を使って関数を呼び出す方法だったよね?
ん、そう。
メソッドとかメンバプロパティも変数を使って呼び出すことができるんだ。
で、この機能をクロージャって呼ぶの。
クロージャ…?
とりあえず、クロージャを使った簡単なスクリプトを書いてみるね。
うん。

<クロージャの使用例(その1)>

class MyDate
{
    // コンストラクタ(何もしません)
    function MyDate(){}

    // デストラクタ(何もしません)
    function finalize(){}

    // 今日の日付を返します
    function getDate()
    {
        var d = new Date();
        return "今日は " + (d.getMonth() + 1) + " 月 " + d.getDate() + " 日です。";
    }
}  // MyDate クラスの定義はここまで

var d = new MyDate();      // MyDate クラスのオブジェクトを作ります
var closure = d.getDate;   // getDate メソッドへの参照を closure に代入します
System.inform(closure());  // 変数 closure を通じてオブジェクト d に対して getDate メソッドを呼び出します
invalidate d;

MyDate クラスは説明しなくても解るよね?
Date クラスを使って今日が何月何日かを返す getDate メソッドがあるね。
うん、そう。
で、クロージャの機能を使ってるのは、最後から3行目の『var closure = d.getDate;』以降の部分ね。
メソッドの名前の後にカッコがついてないってことは、closure にはメソッドへの参照を代入してるってことだよね?
そ。書き方は関数の参照と同じでしょ。
うん、そだね。
じゃあ、その次の行の『System.inform(closure());』を実行するとどうなると思う?
関数の参照の時と同じように考えればいいんだよね。
えっと、『System.inform(d.getDate());』と同じになるんだから、今日が何月何日かが表示されるんじゃないかな?
うん、正解。
じゃあ、結局クロージャって参照のことなの?
んー、まぁ参照って言えば参照なんだけど、クロージャの場合は、コンテキストの情報も持ってるんだ。
コンテキスト?
コンテキストは、メソッドへの参照がどのオブジェクトのものかってことを表してるんだ。
例えば、closure の場合は d がコンテキストになるわけね。
それって、closure は単に getDate メソッドへの参照っていうだけじゃなくて、 d っていうオブジェクトの getDate メソッドへの参照になってるってこと?
そう。だから、getDate メソッドへの参照は、オブジェクトごとに別々に作られるってこと。
なるほどね。
コンテキストについては次回詳しく見ていくから、その時に改めて説明するね。
うん、りょーかい。
あ、そういえば、クロージャってどんな時に使うの?
ん〜、例えばこんな時に使えるかな。

<クロージャの使用例(その2)>

class MyDate2
{
    var day_of_week;  // 曜日の文字列を格納する配列

    // コンストラクタ
    function MyDate2()
    {
        // day_of_week メンバ変数を以下のように初期化します
        day_of_week = ["日""月""火""水""木""金""土"];
    }

    // デストラクタ(何もしません)
    function finalize(){}

    // 現在の年を取得するプロパティ
    property year
    {
        getter()
        {
            var d = new Date();
            return "今は " + d.getYear() + " 年です。";
        }
    }

    // 現在の月を取得するプロパティ
    property month
    {
        getter()
        {
            var d = new Date();
            return "今は " + (d.getMonth() + 1) + " 月です。";
        }
    }

    // 現在の日を取得するプロパティ
    property day
    {
        getter()
        {
            var d = new Date();
            return "今日は " + d.getDate() + " 日です。";
        }
    }

    // 現在の曜日を取得するプロパティ
    property week
    {
        getter()
        {
            var d = new Date();
            return "今日は" + day_of_week[d.getDay()] + "曜日です。";
        }
    }
}  // MyDate2 クラスの定義はここまで


var d = new MyDate2();  // オブジェクトを作ります
// ↓辞書配列にメソッドへの参照を代入します
var closure = %["year" => d.year, "month" => d.month, "day" => d.day, "week" => d.week];
var element;
while(true)
{
    // 入力を受け取ります
    element = System.inputString("""取得する要素名を入力してください。""");
    if(element === void)
        break;  // キャンセルボタンが押されると終了します

    if(closure[element] !== void)
    {
        // 入力された文字列が辞書配列の要素のどれかと一致していれば、
        // その要素に代入されている参照を通じてメソッドを呼び出します
        System.inform(closure[element]);
    }
    else
        System.inform("year, month, day, week のどれかを入力してください。");
}
invalidate d;

まず、MyDate2 クラスのプロパティを見てみて。
year, month, day, week っていうプロパティがあるね。
それぞれ今の年、月、日、曜日を取得するプロパティみたいだね。
ん、そう。
それじゃ、実行してみよっか。
うん。

入力ウィンドウ

これって、何を入力したらいいの?
year』って入力してみて。
はーい。

year と入力した時のメッセージ>

今は 2007 年です。

これって、year プロパティを参照したってことだよね?
ん、そういうこと。
あと、『month』『day』『week』も試してみて。
おっけー。

month と入力した時のメッセージ>

今は 3 月です。

day と入力した時のメッセージ>

今日は 13 日です。

week と入力した時のメッセージ>

今日は火曜日です。

month, day, week って入力すると、それぞれ month, day, week プロパティを参照するってことだよね?
そ。じゃ、スクリプトを見ていこっか。
うん。
まず、MyDate2 クラスのオブジェクトを作った後に、d のプロパティへの参照の辞書配列を作ってるでしょ。
うん、closure っていう辞書配列の "year", "month", "day", "week" っていう要素に dyear, month, day, week プロパティへの参照が代入されてるね。
この辞書配列の要素って、さっき入力した文字列なの?
そうそう。
それをチェックしてるのが『closure[element] !== void』って部分。
element って inputString メソッドの戻り値だから、入力された文字列だよね。
だから closure[element]void じゃないってことは、 入力された文字列が "year", "month", "day", "week" のどれかってことになるんだ。
え、そうなの?
うん。element"year", "month", "day", "week" 以外だと、 closure[element]void になるんだ。
それって、"year", "month", "day", "week" 以外の要素にはまだ何も代入されてないから?
ん、そうだよ。
で、辞書配列の要素には year, month, day, week プロパティへの参照が入ってるわけだから…
入力された文字列によって、どのプロパティを参照するかが決まるってこと?
そういうこと。
クロージャを使うと、条件分岐を使わなくても、入力された文字列に応じて別々のプロパティを簡単に参照できるんだ。
なるほどねー。
今回は4つしかプロパティがなかったから、クロージャを使うメリットはそんなにないかもしれないけど、 プロパティやメソッドがもっと多かったり、複雑な処理をする場合はクロージャを使うと便利かもね。
う〜ん、でもクロージャをうまく使ってスクリプトを書くのって結構難しそうかも…
まぁ大抵の場合はクロージャを使わなくても同じ動作をするスクリプトが書けると思うから、 クロージャは余裕があったら使ってみてね。
うん、りょーかい。
クロージャについてはこんなところかな。
それじゃ、また次回ね。


前へ | TOP | 次へ