条件文は、指定された式の値に応じて、他の文を実行したり、飛ばしたりします。条件文はコードの流れの分かれ目であり、「分岐」と呼ばれることもあります。ここで、コードの流れを JavaScript インタプリタが追っているところを想像してみてください。この中で、条件文は、コードの流れが 2つ以上に分岐する部分にあたります。インタプリタはどの分岐を選ぶかを決定しなければなりません。
この後、項を分けて、JavaScript の基本的な条件文である if/else 文を説明します。さらに、もっと複雑な分岐文である switch についても説明します。
if
文は、JavaScript が条件を判定し、条件付きで文を実行するための基本的な制御文です。if
文には 2つの書式があります。
if
文の第一の書式は次のとおりです。
if (expression)
statement
この書式では、まず expression
を評価し、その結果が true
と評価できる場合に statement
を実行します。式の評価結果が false と評価できる場合には statement
を実行しません( true と評価できる値と、false と評価できる値については、「論理値」を参照)。次の例を見てください。
if (username == null)
// username が null または未定義の場合、
username = "John Doe";
// 定義する。
あるいは次のように記述することもできます。
// username が null、未定義値、false、0、""、NaN の場合、新たに値を設定する。
if (!username) username = "John Doe";
式を囲んでいる丸括弧は、if
文の書式の一部として必ず記述しなければならないことに注意してください。
JavaScript の構文では、if
キーワードの後に、式を丸括弧で囲んで記述し、その後に文を 1つだけ記述します。しかし、文ブロックを使って複数の文を 1つにまとめることで、複数の文を記述できます。次の例を見てください。
if (!address) {
address = "";
message = "Please specify a mailing address.";
}
if
文のもう 1つの書式は、else
句を含むものです。式の評価結果が false
の場合に、else
句が実行されます。第二の書式は次のとおりです。
if (expression)
statement1
else
statement2
この書式の場合、expression
の評価結果が true
と評価される場合は statement1
を実行し、それ以外の場合は statement2
を実行します。実例を以下に示します。
if (n == 1)
console.log("You have 1 new message.");
else
console.log("You have " + n + " new messages.");
else
句を伴う if
文を入れ子にする場合は、else
句と if
文の対応関係に十分気を配る必要があります。次の例を見てください。
i = j = 1;
k = 2;
if (i == j)
if (j == k)
console.log("i equals k");
else
console.log("i doesn't equal j");
// これは変だ!
この例には、if
文が 2つあります。どちらの if
文が else
句に対応するのでしょうか。インデントを見れば、先頭(外側)の if
文のつもりであることがわかりますが、実は JavaScript は次のように解釈します。
if (i == j) {
if (j == k)
console.log("i equals k");
else
console.log("i doesn't equal j");
// これは誤りだ!
}
JavaScript の場合、else
句は直近の if
文に対応します。この規則は、ほかのプログラミング言語でもだいたい同じです。中括弧( {}
)を使って次にように記述すれば、対応関係が明解になります。これなら誤解もないし、コードの保守やデバッグも容易です。
if (i == j) {
if (j == k) {
console.log("i equals k");
}
}
else {
// これなら大丈夫!
console.log("i doesn't equal j");
}
if
文と else
句の本体( while
ループなどの複合文も含む)が 1つの文しかない場合でも、あえて中括弧で囲むプログラマがたくさんいます。当サイトでは、使っていないところもありますが、一貫してこのような表記方法を使うようにすれば、上記のような問題を予防することができます。
条件の判定結果に基づいて 2つのコードのどちらか一方を実行するには、if/else
文が便利なことがわかりました。しかし、実行するコードが 3個以上ある場合はどうしたらよいのでしょうか。1つのやり方は、else if
文を使用することです。厳密には JavaScript の文とは言えないのですが、if/else
を繰り返し使用するときに、else if
もよく使われます。次の例を見てください。
if (n == 1){
// コードブロック #1 を実行する。
}
else if (n == 2) {
// コードブロック #2 を実行する。
}
else if (n == 3) {
// コードブロック #3 を実行する。
}
else {
// すべての else が成立しない時には、コードブロック #4 を実行する。
}
このコードには、特別なものは何もありません。一連の if
文があり、それぞれの if
文が前の文の else
句の一部になっているだけです。入れ子を利用した従来のコードを以下に紹介しますが、このやり方より else if
文のほうがすっきりします。
if (n == 1){
// コードブロック #1 を実行する。
}
else {
if (n == 2) {
// コードブロック #2 を実行する。
}
else {
if (n == 3) {
// コードブロック #3 を実行する。
}
else {
// すべての else が成立しない時には、コードブロック #4 を実行する。
}
}
}
if
文は、プログラムの実行の流れを分岐させるものです。また、else if
文を使って多重分岐させることもできます。しかし、分岐条件で使用する式が 1つだけの場合、このやり方は必ずしもベストだとは言えません。複数の if
文で同じ式を何回も評価するのは無駄です。
このような問題を解決するために switch
文が用意されています。先頭にキーワード switch
を記述し、その後ろに、丸括弧で囲んで式( expression
)を、そして、中括弧に囲んで一連の文( statements
)からなるコードブロックを記述します。
switch(expression) {
statements
}
しかし、switch
文の完全な書式を示すとなると、もっと複雑になります。コードブロック内のさまざまな場所に、「 case expression:
」という書式の case
ラベルを記述します。case
文はラベル文と似ています。ただし、ラベル文では文に名前(ラベル)を付けますが、case
文では文に式を関連付けます。switch
文が実行されると、expression
の値を求め、その値に一致する case
ラベルを探します(一致するかどうかの判定は、===
演算子と同じ比較で判定します)。一致する case
ラベルがあれば、その case
ラベルの後ろに続く最初の文からコードブロックを実行します。一致する case
ラベルがなければ、「 default:
」という特別なラベルを探し、もしあれば、この default:
ラベルの後ろに続く最初の文からコードブロックを実行します。一致する case
ラベルもなく、default:
ラベルもなければ、そのコードブロックをスキップします。
switch
文を言葉で説明するのはかなり大変です。むしろ実例で説明するほうがわかりやすいでしょう。前の項で紹介した入れ子型の if/else
文を switch
文で記述すると、次のようになります。
switch(n) {
case 1:
// n == 1 の場合、ここから開始する。
// コードブロック #1 を実行する。
break;
// ここで中断する。
case 2:
// n == 2 の場合、ここから開始する。
// コードブロック #2 を実行する。
break;
// ここで中断する。
case 3:
// n == 3 の場合、ここから開始する。
// コードブロック #3 を実行する。
break;
// ここで中断する。
default:
// すべての else が成立しない場合、
// コードブロック #4 を実行する。
break;
// ここで中断する。
}
上記のコードで、それぞれの case
句の最後にキーワード break
があることに注意してください。break
文が実行されると、switch
文の最後に処理が移動し、その次の文から実行を再開します。switch
文の case
ラベルは、実行すべきコードの「開始点」を示すだけで、「終了点」は示していません。したがって、break
文を省略すると、expression
の値に一致した case
ラベルの後ろにあるコードブロックから処理を開始し、コードブロックの終わりまで一連の文を処理していきます。このように case
ラベルを次々に処理していくほうがよい場合もまれにはありますが、通常は switch
文の各 case
句の最後に break
文を記述することをお勧めします。なお、関数内に switch
文を記述する場合は、break
文の代わりに return
文が使えます。どちらでも switch
文を終了できます。
さてここで、もう少し実践的なコード例を紹介しましょう。値の型に応じて値を文字列に変換する例です。
function convert(x) {
switch(typeof x) {
case 'number':
// 数値を 16進数に変換して返す。
return x.toString(16);
case 'string':
// 文字列を引用符で囲んで返す。
return '"' + x + '"';
default:
// 上記以外の型の場合、通常の方法で変換する。
return String(x);
}
}
ここで紹介した 2つの例では、case
キーワードの後ろに、数値リテラルと文字列リテラルを記述しました。実際、このような使い方をする場合がほとんどです。ただし、ECMAScript 標準では、case
ラベルに任意の式が記述できるようになっています。
switch
文は、switch
キーワード直後の式を評価した後に、case
ラベルの式を評価します。値が一致する case
ラベルが見つかるまで、コードに記述された順に case
ラベルの式を評価していきます。値は、等値演算子( ==
)ではなく、同値演算子( ===
)を使って比較されます。つまり、型変換は行われません。
switch
文が実行されるときに、すべての case
式が評価されるわけではないので、case
式に関数呼び出しや代入のような副作用を持つような式を書くのは避けたほうがよいでしょう。case
ラベルの式には、できるだけ定数を書くようにしてください。
前述したように、switch
文の expression
に一致する case
ラベルが存在しない場合、switch
文は default
ラベルから実行を行います。もしも default
ラベルが存在しない場合は、switch
文のブロック全体を実行しません。前の例では、default
ラベルは switch
文の最後に記述していました。論理的には、最後に記述するべきです。また、最後に記述するのが一般的でもあります。ただし実際には、switch
文のコードブロック中であれば、どこに記述してもかまいません。