Section 1.12 変数の有効範囲

前回は何で例外が起きちゃったの?
『変数の有効範囲』を考えてなかったからだよ。
変数の有効範囲…ってどういうこと?
if とか while の中のスクリプトに2つ以上の命令が入ってる時には、 {} で囲まれた部分にスクリプトを書いたよね。
例えばこんなふうに。

<正しいスクリプト>

var input;

while(true)
{
    input = System.inputString("文字列を入力してください。""""");
    if(input !== void)
        break;
}

System.inform("入力された文字列は『" + input + "』です。");

うん、確かにそう書くよね。
この {} で囲まれた部分をブロックって呼ぶんだけど、 ブロックの中で宣言された変数は、そのブロックの中でしか使えないんだ。
えっ、そうなの!?
宣言した後はずっと使えるんじゃないの?
上のスクリプトの場合は input がブロックの外にあるから、宣言した後はずっと使えるんだけど、 こんなふうにブロックの中で宣言すると、inputwhile ブロックの中でしか使えないんだ。

<正しくないスクリプト>

while(true)
{
    var input = System.inputString("文字列を入力してください。""""");
    if(input !== void)
        break;
}  // ここから先は input は使えません

System.inform("入力された文字列は『" + input + "』です。");

試しに実行してみて。
うん。
……あ、ホントだ。文字列を入力して OK ボタン押したら『メンバ"input"が見つかりません』っていう例外が起きたね。
でもなんでこんなふうになってるの?
もし変数を宣言した後はずっと使えるようになってたら、 例えばブロックの中だけで一時的に変数を使いたい時でも、 それまでに宣言した変数の名前と重ならないように気をつけないといけないでしょ。
もし名前が重なっちゃってたら、値が書き換えられちゃうってこと?
ん、そういうこと。うっかり変数の値を書き換えちゃったら、動作がおかしくなるかもしれないからね。
だから、ちょっとの間しか使わない変数はブロックの中に入れて、色んな所で使う変数だけをブロックの外で宣言すれば、 間違って変数の値を書き換えちゃうミスを減らせるってワケ。
なるほどね〜。
まとめると、ブロックの中からブロックの外の変数は使えるけど、 ブロックの外からブロックの中の変数は使えないってことだね。

var a = 1;

{
    var b = 2;
    System.inform("a の値は " + a + " です。");  // ○ブロックの中ではブロックの外の変数が使えます
    System.inform("b の値は " + b + " です。");  // ○ブロックの中ではブロックの中の変数も使えます
}

System.inform("a の値は " + a + " です。");  // ○ブロックの外ではブロックの外の変数が使えます
System.inform("b の値は " + b + " です。");  // ×ブロックの外ではブロックの中の変数は使えません

あ、ちょっと質問。
ん?
ブロックには if とかつけなくてもいいの?
うん、こんなふうに何もつけずにブロックを書くこともできるよ。
こうすると {} が無い時と同じように、 普通にブロックの中身が実行されるんだ。
へぇ、そうなんだ。
あと、こんなふうにブロックの中と外で同じ名前の変数を作ることもできるんだ。

var a = 1;  // ブロックの外の a

{
    var a = 2;  // ブロックの中の a
    System.inform("a の値は " + a + " です。");
}

System.inform("a の値は " + a + " です。");

ちょっと実行してみて。
うん。
……最初に「a の値は 2 です。」って表示されて、 次に「a の値は 1 です。」って表示されたね。
つまり、ブロックの外の a とブロックの中の a は同じ名前だけど違う変数ってこと。
で、ブロックの中で a って言うと、ブロックの中で宣言されてる a の方を指すんだ。
ブロックの外で a って言うと、もちろんブロックの外で宣言されてる a の方になるよ。
へぇ…でもなんかちょっとややこしいかも。
ま、確かに普通はブロックの外と中で違う名前にした方がわかりやすいよね。
だね。
それじゃ、前回のスクリプトを直してみよっか。
はーい!
まず、このスクリプトのどこが間違ってたと思う?
えーっと… エラーメッセージに「メンバ"i"が見つかりません」って表示されてたから、 i の宣言が間違ってるんだと思うんだけど…
うんうん。
iif ブロックの中で宣言してるけど、 ブロックの外側にある while の条件式のところでも使ってるから、これが間違いかな。
ん、そうだね。
じゃあ、i はどこに宣言すればいい?
えっとね… while の条件式はどのブロックにも入ってないから、 iwhile ブロックの外に宣言しなきゃいけないんじゃないかな。
じゃあ、スクリプトを書き直してみて。
うん。

<修正したスクリプト>

var value, i;

do
{
    // 正しい値が入力されるまでこの部分を繰り返し実行します
    value = System.inputString("何分後?""1 以上 1439 以下の数字を入力してください。""");
    if(value !== void)
    {
        var ch;
        for(i = 0; i < value.length; i++)
        {
            ch = value.charAt(i);     // i 文字目を取得します
            if(ch < "0" || ch > "9")  // ch が数字("0"〜"9")でない → 数値でない
                break;
        }
    }
}while((value !== void) && (i < value.length || (+value < 1 || +value > 1439)));

if(value === void)
{
    // value が void → キャンセルボタンが押された時の処理をします
    System.inform("キャンセルされました。");
}
else
{
    // value が void でない → OK ボタンが押された時の処理をします
    value = +value;
    var d = new Date();
    var hour = d.getHours();
    var minute = d.getMinutes() + value;
    hour += minute \ 60;
    minute %= 60;  
    hour %= 24;  
    System.inform("今から " + value + " 分後は " + hour + " 時 " + minute + " 分です。");
}

うん。
これでいいと思うよ。
じゃ、確かめてみよっか。
うん。
実行して、「100」って入力して、OK。
……あ、今度はちゃんと 100 分後の時刻が表示されたよ!
次は数値じゃない文字列を入力してチェックね。
じゃあ「10a」って入力して、OK。
……また入力ウィンドウが表示されたよ。
ん、これで OK だね。
スクリプトが複雑になってくると、一時的にしか使わない変数はできるだけブロックの中に入れるようにした方がいいんだけど、 有効範囲の外で変数を使っちゃうミスをしないように気をつけてね。
うん、わかった!
じゃ、今回はここまで。
また次回ね。


前へ | TOP | 次へ