第5回 条件分岐:TypeScriptで学ぶJavaScript入門(5/5 ページ)
プログラミング初心者向けのTypeScript入門連載の第5回は条件分岐の方法についてじっくりと解説する。TypeScriptでプログラミングへの理解を一歩深めよう。
if ... else文を使った実用的な例
ここまでは基本的な知識だが、少し実用的な例も示しておこう。以下のサンプルは、点数を入力すると評価が表示される簡単なプログラムだ。この段階では謎の記述もいくつかあると思うが、if ... else文のネストに注目して、プログラム内のコメントを参考に理解してもらうといいだろう。
// 出力
var rank: string[] = ["不可", "可", "良", "優"];
// 入力
var score_data = document.createElement('input'); // 入力ボックス
var rank_text = document.createElement('div'); // 成績表示用
// 作業用(内部)
var score, rnum: number;
//
score_data.type = "number"; // 入力ボックスを数値専用にする
score_data.addEventListener("keydown", showText, false); // キーを押したらshowText関数を実行する……(1)
document.body.appendChild(score_data); // ドキュメントの本文に入力ボックスを追加……(2)
document.body.appendChild(rank_text); // ドキュメントの本文にテキストを追加
// showText関数(点数に対する評価を表示)
function showText() {
if (event.keyCode == 13 || event.keyCode == 9) { // [Enter]キーまたは[Tab]キーを押したら……(3)
var s: number = score_data.valueAsNumber; // 入力ボックスから数値を取得
if (s < 60) {
rnum = 0;
} else if (s < 70) {
rnum = 1;
} else if (s < 80) {
rnum = 2;
} else {
rnum = 3;
}
rank_text.innerText = rank[rnum]; // 成績を表示
}
}
このプログラムでは、Webページに入力ボックスと表示用の領域を追加し、入力された点数に従って、評価を表示する。入力ボックスで[Enter]キーまたは[Tab]キーが押されたら、点数から評価を求め、表示用の領域にテキストを表示するという流れになっている。ここでは、押されたキーを判定するために、論理和を求める||演算子を使っていることと、if ... else文のネストがこれまでより1つ深くなっていることにだけ注目してもらうといいだろう。実行例は以下のようになる。
if ... else文以外のプログラムの詳細については、回を追って説明を加えていくので、少しずつ理解を深めていけばいいが、(1)のaddEventListerメソッドを使って、入力ボックスでキーが押されたとき(keydown)に実行する関数(showText関数)が呼び出されるようにしていること、(2)のappendChildメソッドで入力ボックスを追加していること、(3)event.KeyCodeで押されたキーを調べていることがポイントだ。[Enter]キーを表すキーコードは13、[Tab]キーを表すキーコードは9となっている。
if...else文の落とし穴(2)
if ... else文の書き方に直接関連することではないのだが、少し注意しておいた方がいいと思われる事柄を2点だけ拾い上げておこう。
1点目は、前回も取り上げたが、条件を表す式を日常的な感覚で書くと思わぬ結果になってしまうことがあるということ。例えば、献血に行くとさまざまな検査をしてもらえるのだが、その通知を見ると、男性の赤血球数(RBC:Red Blood Cell)は425〜570×104µLが標準値となっている。標準値の範囲に入っているかどうかを調べたいときには、以下の(1)のように書きたくなるが、正しい書き方は(2)である。
if (425 < rbc < 570) ... (1)(誤った書き方)
if (rbc > 425 && rbc < 570) ... (2)
理由は、(1)では「425 < rbc」の結果がtrueまたはfalseとなるからだ。次の比較は「true < 570」か「false < 570」となってしまい、trueは1、falseは0と見なされるので、常に条件が成り立ってしまう。これだと赤血球数が少なくても標準値の範囲という結果になってしまう。
ただし、TypeScriptでは変数の型をきちんとチェックしているので(1)のような書き方にするとコンパイルエラーとなる。JavaScriptのプログラムは作られ、実行もできるので、気付かずに使ってしまうことのないよう、注意しよう。
2点目は文字列を取り扱うメソッドが返す値を勘違いして使ってしまうこと。例えば、文字列の一部に含まれているある文字列の位置を得るためにindexOfメソッドが用意されている。例えば、文字列“hoge”の中に含まれている“ge”の位置を知りたいときは、以下のように書く。
var pos: number;
var str: string = "hoge";
pos = str.indexOf("ge");
alert(pos);
返される値は先頭を0とした文字の位置なのだが、検索文字列が見つからないときは-1が返される。このとき、検索文字列が見つかったら、というつもりで、(1)のように書いてしまうことがある。しかし、正しい書き方は(2)である。
var str: string = "hoge";
if(str.indexOf("ge")) alert("見つかった"); ... (1)(誤った書き方)
if(str.indexOf("ge") != -1) alert("見つかった"); ... (2)
検索文字列が元の文字列の2文字目以降に含まれる場合は(1)でもうまくいくのだが、検索文字列が見つからない場合にも見つかったことになってしまう。検索文字列が見つからない場合はindexOfメソッドは-1を返すが、JavaScriptでは0がfalse、0以外がtrueと見なされてしまうからだ。-1はtrueと見なされるので、条件が満たされたことになるわけだ。さらに、検索文字列が元の文字列の先頭にある場合には、逆に見つからなかったことになってしまう。この場合、indexOfメソッドが0を返すので、(1)の条件式はfalseと見なされるからだ。“ge”の部分を“xx”(見つからない場合)や“h”(先頭にある場合)に書き替えて試してみるといい。
こういったミスを犯すと、うまくいかないパターンが読みづらく、原因を突き止めにくいので、延々と悩むことにもなりかねない。注意すべき点はメソッドが返す値だ。indexOfメソッドの仕様を見ると、検索文字列が見つからない場合は(falseではなく)-1を返す、とちゃんと書いてあるはずだ。
以下の表で、trueとfalseがどのように取り扱われるかをもう一度確認しておこう。
ブール値 | → | 整数として評価 |
---|---|---|
true | → | 1 |
false | → | 0 |
整数 | → | ブール値として評価 |
---|---|---|
0以外 | → | true |
0 | → | false |
trueとfalseの取り扱い |
switch文による多分岐
if文はいわば汎用的な条件分岐の構文だが、switch文は1つの変数や式が特定の値であるかどうかを判定して多分岐させるときに便利な構文である。簡単な例を見てみよう。
var fortune: string;
var n: number;
n = Math.floor(Math.random() * 7); // 0〜6までの整数の乱数……(1)
switch (n) {
case 0:
case 1:
fortune = "大吉";
break;
case 2:
fortune = "中吉";
break;
case 3:
case 4:
fortune = "小吉";
break;
case 5:
fortune = "凶";
break;
default:
fortune = "大凶";
}
alert(n + ":" + fortune);
(1)では0以上7未満(=6以下)の整数の乱数を作り、nに代入している。Mathクラスのrandomメソッドを使うと0以上1未満の小数の乱数が作れるので、それを7倍すれば0以上7未満の小数値になる。さらにMathクラスのfloorメソッドを使って小数点以下を切り下げれば0以上7未満の整数になる。その値を基におみくじを表示しようというわけだ。プログラムを簡単にするために、運勢の種類は一般的なおみくじよりは少なくしてあるが、大吉と小吉の出る確率は高くしてある。
プログラムの実行例は以下の通り。
では、switch文の書き方を細かく見ていこう。
switch文のポイントを以下に箇条書きで示しておく。
- switchの後の()の中の変数や式の値によって実行する文が変えられる
- ()の中の変数や式の値がcaseの後に指定した値に一致すれば、それ以降の文が全て実行される
- 1つのcaseの中には複数の文を書いてもよい
- ただし、break文があると、そこでswitch文を抜けて、次の文に進む
- defaultは他のcaseで指定していない全ての値に一致する(通常は「上記以外の場合」を表すために、最後に書かれる)
注意すべき点は、一致した箇所の文だけが実行されるのではない、ということである。例えば、「case 0:」には何も書かれていないが、変数nの値が0に一致した場合は何もせずにswitch文を抜けるのではなく、それ以降を全て実行する。しかし、「case 1:」の最後にbreak文が書かれているので、そこでswitch文を抜ける。
つまり、一致した箇所の文だけを実行したいときには、その部分の最後にbreak文を書いておく必要があるということだ。もし、break文を忘れると、意図せぬ文が実行されてしまうので注意が必要だ。例えば、「case 2:」の最後に書かれているbreak文を忘れてしまうと、変数nの値が2に一致したときには変数fortuneに「中吉」が代入されるが、(break文がないので)そのまま次に進んで「case 3:」以降が実行される。つまり「中吉」が代入されていた変数fortuneに「小吉」が代入されてしまう。要するに「中吉」が一切出ないおみくじになってしまうというわけだ。
switch文については、一般的な形式やフローチャートを示さなくても、図5の解説だけで十分に理解できると思われるので、この程度にとどめておこう。
?演算子
最後に、?演算子による条件分岐についても見ておく(条件演算子ともいう)。?演算子を使うと、条件によって利用する式が変えられる。変数に代入する値を条件によって変えるときに便利な演算子である。
これも、まず例を見ておこう。ゴールド会員なら価格を2割引とし、それ以外なら1割引とするだけのプログラムだ。割引金額を表示するものとする。
var discount: number; // 割引金額
var price: number = 1000; // 1000円の商品
var rank: string = "gold"; // 顧客ランク(goldランクとする)
// goldなら2割引、それ以外なら1割引
discount = (rank == "gold" ? price * 0.2 : price * 0.1); // (1)
alert(discount);
このプログラムでは、変数rankに“gold”を代入しているので、実行しなくても結果は分かるが、一応実行例を示しておく。
では、?演算子の書き方を図解で見てみよう。以下の図は(1)の右辺を抜き出したものである。
一般的な形式は、以下のようになる。式1がtrueであれば式2の値を返し、falseであれば式3の値を返す。
?演算子の構文
式1 ? 式2 : 式3
(1)では、?演算子によって求めた式の値を変数discountに代入している。?演算子の優先順位は代入の=演算子よりも高いので、()はなくてもプログラムは正しく動くが、()を付けておいた方が、意味が分かりやすいだろう。
なお、?演算子をネストさせることもできる。例えば、シルバー会員なら1.5割引という条件が加わるなら、(1)は以下のような文になる。
discount = (rank == "gold" ? price * 0.2 : (rank == "silver" ? price * 0.15 : price * 0.1));
とはいえ、あまり読みやすいとはいえないので、条件が複雑になれば素直にif ... else文かswitch文を使った方がいい。ちなみに、今の例をswitch文で書けば以下のようになる。
switch (rank) {
case "gold":
discount = price * 0.2;
break;
case "silver":
discount = price * 0.15;
break;
default:
discount = price * 0.1;
}
ここでも、break文を忘れないようにしよう。
今回はTypeScriptにおける条件分岐について、if ... else文、switch文、?演算子を取り上げた。
次回は実用的なプログラムの作成には必要不可欠な繰り返し処理に進む。繰り返し処理についてはさまざまなバリエーションがあるので、2回に分けて解説する。
Copyright© Digital Advantage Corp. All Rights Reserved.