Section 1.20 関数のまとめ

今回は関数のまとめってことで、関数を使って §1.12 のスクリプトを書き直してみようと思うんだ。
それって、今から 100 分後とかの時刻を表示するスクリプトのことだよね。
そ。今回はこのスクリプトを4つの関数に分割するよ。
4つの関数?
ん、この4つ。

<今回作る関数>

  1. isNumber 関数
    第1引数…value(文字列)
    動作………value が数値(0以上の整数)と見なせるかどうかをチェックします。
    戻り値……value が数値と見なせれば真(true)、見なせなければ偽(false)を返します。

  2. toNumber 関数
    第1引数…value(文字列)
    動作………value を数値に変換します。
    戻り値……value を数値に変換した値を返します。ただし、引数が数値と見なせない場合や、範囲外の数値の場合は void を返します。

  3. getInput 関数
    引数………なし
    動作………入力ウィンドウを表示して、数値を受け取ります。不正な値が入力された場合は、もう一度入力ウィンドウを表示します。
    戻り値……OK ボタンが押された場合は入力された数値、 キャンセルボタンが押された場合は void を返します。

  4. calculateTime 関数
    第1引数…value(数値)
    動作………今から value 分後の時刻を計算します。
    戻り値……今から value 分後の時刻を文字列にして返します。

ずいぶん細かく分けるんだねぇ。
その方がそれぞれの関数が何してるかわかりやすいからね。
ふぅん、そうなんだ。
というワケで、まずは isNumber 関数から作っていこっか。
はーい。
isNumber 関数は文字列が引数になってて、引数が数値と見なせれば真、見なせなければ偽を返すの。
これは §1.12 のスクリプトの一部をほぼそのまんま使えるから、とりあえず作ってみて。
それって do〜while の中の if の中身のことだよね。
ん、そう。
え〜っと、『function isNumber(value)』から始めればいいんだから…

isNumber 関数>

// 引数が数値(0以上の整数)と見なせれば真、見なせなければ偽を返します
function isNumber(value)
{
    var i, ch;
    for(i = 0; i < value.length; i++)
    {
        ch = value.charAt(i);     // i 文字目を取得
        if(ch < "0" || ch > "9")  // ch が数字("0"〜"9")でない → 数値でない
            break;
    }

    if(i < value.length)
        return false;  // value が数値と見なせないので false を返します
    else
        return true;   // value が数値と見なせるので true を返します
}

こうだよね。
うん、これで OK。
でも、こうすればもうちょっと簡単に書けるよ。

isNumber 関数(改良版)>

// 引数が数値(0以上の整数)と見なせれば真、見なせなければ偽を返します
function isNumber(value)
{
    var i, ch;
    for(i = 0; i < value.length; i++)
    {
        ch = value.charAt(i);     // i 文字目を取得
        if(ch < "0" || ch > "9")  // ch が数字("0"〜"9")でない → 数値でない
            return false;  // 数値と見なせないことが判ったので false を返します
    }
    return true;  // for ブロックを抜けられるのは value が数値と見なせる場合だけなので true を返します
}

return って for ブロックの中に書いてもいいんだ?
うん。for ブロックの中で return すると、繰り返しの途中でも関数はそこで終わりになるんだ。
じゃ、次は toNumber 関数ね。
toNumber 関数は、引数に指定されてる文字列を数値に変換した値を返すんだよね?
あと、引数が数値と見なせない場合や、範囲外の数値になってる場合は void を返してね。
ちなみに範囲外の数値ってのは 1〜1439 の範囲外の数値ってことね。
数値と見なせるかどうかっていうのは、さっき作った isNumber 関数を使ってチェックしてもいいの?
うん、もちろん。
ん〜、じゃあ…

toNumber 関数>

// 引数(文字列)を数値に変換した値を返します
// ただし、引数が数値と見なせない場合や、範囲外の数値の場合は void を返します
function toNumber(value)
{
    // 引数が数値とみなせない場合は void を返します
    if(isNumber(value) == false)
        return void;

    value = +value;  // 数値に変換します

    // 引数が範囲外の数値の場合は void を返します
    if(value < 1 || value > 1439)
        return void;

    return value;
}

こんな感じかな。
ん、ちゃんと書けてるね。
でしょ〜。
あ、でも『isNumber(value) == false』は『!isNumber(value)』って書くことが多いかな。
あ、そうなんだ。
! 演算子は真と偽を逆にするから、こうすれば isNumber(value) が偽の時に !isNumber(false) が真になるでしょ。
うん、確かにそうなるね。
それじゃ次は getInput 関数。
入力ウィンドウを表示します、っていうのは inputString メソッドを使うってことだよね?
そ。で、OK ボタンが押された場合は入力された数値、キャンセルボタンが押された場合は void を返してね。
これは色んな書き方ができると思うけど、今回は while(true) を使って書いてみて。
while(true) って確か無限ループになるんだったよね。
うん、そう。§1.10 でやったよね。
じゃあ、キャンセルされたりちゃんとした数値が入力されたら break でループから抜ければいいの?
その時はすぐに return しちゃっていいよ。
あ、while ブロックの中でも return できるんだ?
うん、できるよ。
あと、今回は正しくない値が入力された時には「1 以上 1439 以下の数字を入力してください。」っていうメッセージを表示するようにしてね。
わかった。じゃあ…

getInput 関数>

// 入力ウィンドウを表示します
// OK ボタンが押された場合は入力された数値を、キャンセルボタンが押された場合は void を返します
function getInput()
{
    while(true)
    {
        // 入力を受け取ります
        var value = System.inputString("何分後?""1 以上 1439 以下の数字を入力してください。""");
        // キャンセルされた場合は void を返します
        if(value === void)
            return void;

        // 入力された文字列を数値に変換します
        value = toNumber(value);
        // 正しい数値が入力された場合はその値を返します
        if(value !== void)
            return value;

        // 入力された値が正しくない場合は、メッセージを表示してもう一度入力ウィンドウを表示します
        System.inform("1 以上 1439 以下の数字を入力してください。""エラー");
    }
}

こんな感じでどうかな?
うん、ばっちりだね!
やった〜!
じゃ、最後は時刻を返す calculateTime 関数だね。
これって §1.12 のスクリプトの最後にある else ブロックの中身を使えばいいんだよね。
ん、あと戻り値は inform メソッドの引数にしてる文字列でいいよ。
うん、わかった。
え〜と、引数は整数型になってるから最初の value = +value; は要らないよね。
ってことは…

calculateTime 関数>

// 今から value 分後の時刻を返します
function calculateTime(value)
{
    var d = new Date();
    var hour = d.getHours();
    var minute = d.getMinutes() + value;
    hour += minute \ 60;
    minute %= 60;  
    hour %= 24;  
    return "今から " + value + " 分後は " + hour + " 時 " + minute + " 分です。";
}

こうなるよね。
ん、これで OK!
これで完成だね!
まだ関数を呼び出すスクリプト書いてないでしょ。
あ、そっか。忘れてた。
えっと、まず入力ウィンドウを出さなくちゃいけないから、 最初に呼び出すのは getInput 関数だよね?
ん、そだね。
んーっと、getInput 関数の戻り値は、OK ボタンが押されたら数値で、 キャンセルボタンが押されたら void になるんだから…

<関数を呼び出す部分のスクリプト>

var value = getInput();  // 入力を受け取ります

if(value !== void)
    System.inform(calculateTime(value));  // OK ボタンが押されたら時刻を表示します
else
    System.inform("キャンセルされました。");  // キャンセルボタンが押されたらメッセージを表示します

これでいいかな?
ん、今度こそ完成だね!
やっとできた〜!
あ、いい機会だからここで1つ新しい演算子を紹介しとくね。
ん? どんな演算子?
条件演算子っていう演算子。
これを使うと、上のスクリプトの ifelse の部分が1行で書けるんだ。
こんなふうに。

<関数を呼び出す部分のスクリプト(条件演算子使用)>

var value = getInput();  // 入力を受け取ります

// 押されたボタンに対応したメッセージを表示します
System.inform(value !== void ? calculateTime(value) : "キャンセルされました。");

確かに1行になってるみたいだけど…どれが条件演算子なの?
?: だよ。
じゃあ、条件演算子って ?: の2種類あるってこと?
ううん、そうじゃなくて、?: で1つの演算子なんだ。
えっ、それってどういうこと?
条件演算子は三項演算子なんだ。
三項演算子?
名前の通り、項を3つとる演算子。
使い方はこんな感じ。

<条件演算子の使い方>

(条件式)?(条件が真の場合の値):(条件が偽の場合の値)

えっと、じゃあ条件式が『value !== void』で、 これが真だったら inform メソッドの引数が『calculateTime(value)』になって、 偽だったら『"キャンセルされました。"』になるってこと?
うん、そういうこと。
ちゃんと ifelse を使ったスクリプトと同じ結果になるでしょ。
あ、ほんとだね。
単純な条件分岐をする時は条件演算子を使うこともあるから覚えといてね。
はーい。
というわけで、これが完成版のスクリプト。

<完成版スクリプト>

// 引数が数値(0以上の整数)と見なせれば真、見なせなければ偽を返します
function isNumber(value)
{
    var i, ch;
    for(i = 0; i < value.length; i++)
    {
        ch = value.charAt(i);     // i 文字目を取得
        if(ch < "0" || ch > "9")  // ch が数字("0"〜"9")でない → 数値でない
            return false;  // 数値と見なせないことが判ったので false を返します
    }
    return true;  // for ブロックを抜けられるのは value が数値と見なせる場合だけなので true を返します
}

// 引数(文字列型)を数値に変換した値を返します
// ただし、引数が数値と見なせない場合や、範囲外の数値の場合は void を返します
function toNumber(value)
{
    // 引数が数値とみなせない場合は void を返します
    if(!isNumber(value))
        return void;

    value = +value;

    // 引数が範囲外の数値の場合は void を返します
    if(value < 1 || value > 1439)
        return void;

    return value;
}

// 入力を求めるウィンドウを表示します
// OK ボタンが押された場合は入力された数値を、キャンセルボタンが押された場合は void を返します
function getInput()
{
    while(true)
    {
        // 入力を受け取ります
        var value = System.inputString("何分後?""1 以上 1439 以下の数字を入力してください。""");
        // キャンセルされた場合は void を返します
        if(value === void)
            return void;

        // 入力された文字列を数値に変換します
        value = toNumber(value);
        // 正しい数値が入力された場合はその値を返します
        if(value !== void)
            return value;

        // 入力された値が正しくない場合は、メッセージを表示してもう一度入力を求めます
        System.inform("1 以上 1439 以下の数字を入力してください。""エラー");
    }
}

// 今から value 分後の時刻を返します
function calculateTime(value)
{
    var d = new Date();
    var hour = d.getHours();
    var minute = d.getMinutes() + value;
    hour += minute \ 60;
    minute %= 60;  
    hour %= 24;  
    return "今から " + value + " 分後は " + hour + " 時 " + minute + " 分です。";
}
// 関数の定義はここまで

var value = getInput();  // 入力を受け取ります

// 押されたボタンに対応したメッセージを表示します
System.inform(value !== void ? calculateTime(value) : "キャンセルされました。");

わ、結構長くなったね〜。
でも、それぞれの処理を関数にしたから、全体的には読みやすくなってるでしょ。
そだね。どこでどんな処理をやってるのかが解りやすくなったね。
それに、こうやって関数にしとくと、別のスクリプトを書く時でも使えるからね。
例えば、何日後かの日付を表示するスクリプトを作る時とかには、isNumber 関数や toNumber 関数はそのまま使えるよ。
なるほどね〜。
それじゃ、第1章はこれで終わり。
第1章って色んなことやったよね〜。
うん、そうだね。
でも §0.3 の目標が達成できるのは第3章になるから、まだ半分も来てないくらいだよ。
えっ、まだそんなところなのぉ?
それだけ TJS には機能がいっぱいあるってこと。
でもそれをちゃんと理解できれば、KAG みたいなシステムを自分で作ることだってできるかもね。
そ、それはちょっと無理なんじゃ…
ま、確かに KAG レベルのスクリプトを書こうと思ったら、よっぽど勉強しなくちゃいけないけどね。
でも、KAG 用のプラグインとかなら十分作れるようになると思うよ。
そだね。とりあえずその辺を目指そうかな〜。
そのためにはクラスを理解しなくちゃね。
クラスって System とか Date のこと?
ん、そう。System とか Date は元々用意されてるクラスだけど、 第2章ではクラスを使うだけじゃなくて、作ってみるからね。
クラスって作れるの?
うん、もちろん。
KAG のプラグインを作る時とかにもクラスを作るよ。
へぇ、そうなんだ…
でもクラスを作るのって難しいんじゃない?
基本的なとこからやっていけば大丈夫だよ。
うん、そだね。ここまで来れたんだし、次も何とかなるかな。
そうそう。
というわけで、次回から第2章、クラスについて見ていくから、しっかりついてきてね!
はーい!


前へ | TOP | 次へ