switch文で複数の分岐から1つを選ぶ
switchは、1つの値をいくつかの決まった候補と比較したいときに使う制御構文です。if/else if/elseを連ねても同じことはできますが、同じ変数を3回も4回もチェックするような場面では、switchのほうが断然読みやすくなります。
基本的な形はこんな感じです。
上から順に読むと、JavaScriptはまず day を評価し、それを各 case のラベルと照合して、一致したブロックを実行します。どのケースにも当てはまらなかったときは default が受け皿になります。ちょうど最後の else のような役割ですね。読む順番は 値 → case → コード です。
switch文のマッチングの仕組み
switch の比較は厳密等価、つまり === 演算子で行われます。型変換も曖昧な一致もありません。たとえば case 1: は数値の 1 にはマッチしますが、文字列の "1" には マッチしません 。
マッチするのは2番目の case だけです。「switch が反応しないんだけど…」とハマったときは、フォームの入力値や URL パラメータから来た値で「文字列 vs 数値」のミスマッチが起きている、というのがだいたい定番の原因です。
処理を止めるのは break の役割
ここが初心者のつまずきポイントです。case ラベルは独立したブロックではなく、あくまで ジャンプ先のマーカー にすぎません。マッチした case に飛び込むと、そこからは次の case ラベルもお構いなしに、1行ずつ下へ下へと実行が続きます。止まるのは break、return、あるいは switch の末尾に到達したときだけです。
break を書かないとどうなるか、見てみましょう。
マッチするのは "editor" のはずなのに、実行結果には 編集可能、閲覧可能、ログイン中 まで出てしまいます。これがいわゆるフォールスルーで、処理を止めるものが何もないので後続の case にそのまま流れ込んでいくわけです。
break を入れてあげれば、ちゃんと想定どおりに動きます。
お約束として、意図的にフォールスルーさせたいとき以外は、各 case の最後に必ず break を書きましょう。
意図的なフォールスルーでケースをまとめる
フォールスルーは必ずしもバグというわけではありません。「これらの case はどれも同じ処理でいい」と表現したいときは、あえて break を省くとスッキリ書けます:
空の case ラベルを並べて書くと、その下のブロックを共有できます。return の後に break が不要な点にも注目してください。関数自体がそこで終了するので、return を書いた時点で switch の残りはすべてスキップされます。
中身のある case 同士で意図的にフォールスルーさせたいときは、あとから読んだ人が「バグだ」と思って“修正”してしまわないよう、コメントを残しておきましょう。
default は必ずしも最後じゃなくていい
慣習的に default は末尾に置きますし、読み手もそこにあると思って読みます。ただ、技術的には単なるラベルのひとつに過ぎません。どの case にも一致しなかったときに実行されるという動作は、書く位置に関係なく同じです。もし default を途中に置いて break を書かなければ、その下の処理にそのままフォールスルーしていきます。素直に最後に置いて break で締める(あるいは後ろに何もないので省略する)のが、将来の自分にとっていちばん親切です。
case内での変数のスコープ
switch 内のすべての case は、1つのブロックスコープを共有しています。そのため、同じ名前の let や const を複数の case で宣言すると、再宣言エラーになります。
switch (x) {
case 1:
let msg = "one";
break;
case 2:
let msg = "two"; // SyntaxError: Identifier 'msg' has already been declared
break;
}
修正方法はシンプルで、各 case の中身を { } でブロック化してあげるだけです。
これで msg はそれぞれのスコープに閉じ込められるので、変数名の衝突も起きません。case の中に数行以上のロジックを書くときは、このパターンを思い出しておくといいでしょう。
switch文とif/elseの使い分け
switchが真価を発揮するのは、1つの値をあらかじめ決まった複数の選択肢と照合するケースです。HTTPステータスコード、Reduxのaction type、コマンド名、enum的な文字列などが典型例ですね。比較対象の値が冒頭に一度だけ登場するので、読み手は case ラベルを目次のように上から順に追っていけます。
一方、次のような場面では if/else のほうが向いています。
- 範囲で比較したいとき(
score >= 90、score >= 75など)。 - 条件に複数の変数や真偽値の式が絡むとき。
- 緩い等価比較や独自の比較ロジックを使いたいとき(
switchは常に===で比較されます)。
最初のパターンについては、オブジェクトをルックアップテーブルとして使うやり方が、今どきの書き方としてよく使われます。
9行のswitchがたったの3行に。ケースが単なるデータの対応付けで、ロジックらしいロジックがないなら、オブジェクト(あるいはMap)のほうが読みやすいことが多いです。switchの出番は、各ケースで実際に 処理 をするときです。
次は for ループ
switchは1つの値を複数の選択肢と照らし合わせる制御構文でした。次に登場するのは「繰り返し」、つまり同じコードブロックを何度も実行する仕組みです。それを担うのがforループ。次の章で見ていきましょう。
よくある質問
JavaScriptのswitch文はどう動くの?
switchは、1つの値を複数のcaseラベルと厳密等価(===)で比較していきます。マッチするケースが見つかるとそこから処理を実行し、breakが出てくるかブロックの終わりに到達するまで動き続けます。どのcaseにも当てはまらなかったときの受け皿として、default句を置くこともできます。
switch文のフォールスルーって何?
caseの最後にbreak(あるいはreturn)を書かないと、そのまま次のcaseの処理まで流れ込んで実行されてしまいます。ラベルがマッチしていなくても、です。これは同じ処理を複数ケースでまとめたいときには便利ですが、バグの原因になることの方が多いです。意図的に使う場合を除いて、caseの末尾には必ずbreakを書く、と覚えておきましょう。
switch文とif/else、どう使い分ければいい?
1つの値を固定の候補と照らし合わせる場面——HTTPステータスコード、アクションタイプ、文字列コマンドなど——ではswitchが向いています。一方、範囲比較や複数変数の条件、真偽値の組み合わせが必要ならif/elseの方が素直です。なおswitchは厳密等価で比較するので、case '1'は数値の1にはマッチしない点に注意してください。