プログラミング(特に JavaScript)では、「ただ上から下へ書いた順に処理を進めるだけ」では対応できない状況が多くあります。たとえば「ある条件のときには別の道を通る」「同じ処理を何回も繰り返す」「エラーが起きたらそれに対応する」など。これらを扱うのが 制御フロー (control flow) や エラー処理 (error handling) の概念です。
以下、大事な要素を順番に見ていきます。
1. ブロック文 (Block statement)
まず、「複数の命令をまとめて扱う」ためのしくみです。波括弧 { … } で囲むことで、複数の文(ステートメント)をひとかたまりとして扱えます。
{
statement1;
statement2;
// …さらに文があれば続く
}
JavaScript例:
while (x < 10) {
x++;
}
JavaScriptここで { x++; } の部分がブロックです。
注意点として、古い var 宣言はこのブロックでスコープ(有効範囲)が分かれない、という性質があります。そのため、ECMAScript 6(ES6)以降では let/const を使うと、ブロック毎のスコープが正しく働きます。
2. 条件分岐 (Conditional statements)
ある条件が真 (true) か偽 (false) かによって処理を分けたいときに使う文です。主に以下のものがあります。
2.1 if … else
最も基本的な条件分岐。条件式が真ならある処理、偽なら別の処理をします。
if (condition) {
// condition が true のとき実行
} else {
// false のとき実行
}
JavaScriptさらに複数の条件を順番にチェックしたい場合は else if を使います。
if (cond1) {
// …
} else if (cond2) {
// …
} else {
// どれにも当てはまらないとき
}
JavaScript「条件式」は真または偽に評価されるものなら何でも使えます(比較演算子、論理演算子など)。
2.2 switch
複数の値を比較して処理を分けたいときに向いています。たとえば変数 x の値が 1, 2, 3 … のどれかで異なる処理をする、というような場面。
switch (expression) {
case value1:
// expression === value1 のときの処理
break;
case value2:
// expression === value2 のときの処理
break;
default:
// どの case にも当てはまらないとき
}
JavaScript重要:break を忘れると、その下のケースも実行されてしまう(フォールスルー)ので注意。
3. 例外 (Exception) とその処理 — throw, try…catch…finally
プログラム実行中に「起きてはいけない事(エラー)」が発生することがあります。たとえば、未定義の変数を参照したり、外部データが不正な形式だったり。これを 例外 (exception) と言い、JavaScript ではそれを “投げる (throw)” ことで知らせ、適切な処理 (catch) をする仕組みがあります。
3.1 throw
自分でエラーを発生させたいときに使います。投げる対象には、文字列やオブジェクト、Error オブジェクトなどを使えます。
throw "エラーだ!";
throw new Error("何かがおかしい");
JavaScriptエラーを投げた場所以降の処理は中断され、例外処理がされるまで外側へ伝播します。
3.2 try…catch
try に書いた処理で例外が発生したら、catch のブロックに処理が移ります。
try {
// 例外が発生する可能性のある処理
} catch (err) {
// err には発生した例外(オブジェクトや値)が入る
}
JavaScripttry内でエラーがなければ、通常通り進み、catchはスキップされます。try内でエラーが起きると、それ以降のtry内の処理は実行されず、すぐにcatchに移ります。
最近の JavaScript では、catch の引数を省略できる構文も使えます(エラーの詳細を使わないとき用)。
3.3 finally
try/catch のあとに finally ブロックを付けると、その中の処理は “例外があってもなかろうと”、常に最後に実行されます。
try {
// …
} catch (err) {
// …
} finally {
// 常に実行される後片付け処理など
}
JavaScriptたとえばファイルを開いたら必ず閉じたい、ネットワーク接続を切りたい、など「必ずやるべき処理」があれば finally に書きます。
注意:finally 内で return や throw を使うと、try/catch の戻り値や例外を上書きしてしまうことがあります。なるべく finally 内で制御フロー (return/throw) を行うのは避けた方が無難です。
3.4 ネスト/再スロー (rethrow)
try…catchをネスト(内側に入れ子)して使うこともできます。内側でキャッチしなかった例外が外側に伝わることもあります。catch内で例外を再びthrowする(再スロー)ことで、外側に例外を伝えることもできます。これは「この例外はこのレベルでは処理できない。上位で処理してね」という意味合いです。
4. エラーオブジェクトと主な例外タイプ
例外をキャッチするときには、どのようなエラーかを知ることが大事です。JavaScript の組み込みエラーには、次のような種類があります。
| エラー名 | 内容の一例 |
|---|---|
ReferenceError | 存在しない変数を参照した |
TypeError | 型が想定と異なる操作をした |
SyntaxError | 文法的に誤りのあるコードを評価しようとした |
RangeError | 数値が範囲外だった |
URIError | URI 関連の関数で不正な文字列を扱った |
捕まえた例外オブジェクトには、主に次のプロパティがあります:name(エラー名)、message(エラー内容の説明)など。
たとえば:
try {
JSON.parse("不正な JSON");
} catch (err) {
console.log(err.name); // SyntaxError など
console.log(err.message); // 具体的なメッセージ
}
JavaScript5. なぜこれらが大事か・使いどころ
初心者から見て「制御フローとエラー処理を使う意味」は、次のような場面で明らかになります。
- 条件に応じて処理を変える:ユーザーがログインしていれば A を、ログインしてなければ B をやる、など。
- 繰り返す処理:配列の全要素に対して同じ処理をしたいとき(ループは別章ですが、“分岐”と組み合わされます)。
- 外部入力やアプリ間連携で不確定性を扱う:サーバーから受け取るデータが必ず正しいとは限らない。例外が起きる可能性があるので、それを予め対策しておきたい。
- 安定性の向上:エラーが起きてプログラム全体が止まるより、例外をキャッチして「代替処理をする」「エラーメッセージを出す」などできた方が良い。
