JavaScript

条件文

 条件文は、指定された式の値に応じて、他の文を実行したり、飛ばしたりします。条件文はコードの流れの分かれ目であり、「分岐」と呼ばれることもあります。ここで、コードの流れを JavaScript インタプリタが追っているところを想像してみてください。この中で、条件文は、コードの流れが 2つ以上に分岐する部分にあたります。インタプリタはどの分岐を選ぶかを決定しなければなりません。

 この後、項を分けて、JavaScript の基本的な条件文である if/else 文を説明します。さらに、もっと複雑な分岐文である switch についても説明します。

if 文

 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つの文しかない場合でも、あえて中括弧で囲むプログラマがたくさんいます。当サイトでは、使っていないところもありますが、一貫してこのような表記方法を使うようにすれば、上記のような問題を予防することができます。

else if 文

 条件の判定結果に基づいて 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 を実行する。
   }
  }
}

switch 文

 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 文のコードブロック中であれば、どこに記述してもかまいません。