JavaScriptの例外とエラーハンドリング
エラーは「問題が起きて、処理が止まるサイン」。怖がるより、うまく受け止める仕組みを覚えるとプログラムがグッと安定します。ここでは初心者向けに、例外(エラー)とtry...catchの使い方を、シンプルな例題で丁寧に説明します。
例外(エラー)ってなに?
- エラーの役割: 間違いを知らせてくれるアラーム。無視するとプログラムが落ちます。
- よくある原因: 打ち間違い、存在しない変数を使った、型が違う、ルール外の値を渡したなど。
- よく使う種類:
- TypeError: 型が合わない(例: 文字列に数値用のメソッドを呼ぶ)
- ReferenceError: 変数が見つからない(例: 宣言してない変数名)
- RangeError: 許可された範囲外(例: 基数は2〜36なのに100を指定)
- SyntaxError: 文法ミス(コードの書き方が間違い)
- Error: 一般的なエラー(自作も可)
try…catchの基本
- 目的: エラーが起きてもプログラム全体が止まらないように「受け止める」。
- 基本形: まずは「まとめて受け止める」から。
try {
// ここでエラーが出るかもしれない
const x = JSON.parse('{"name":"Mio"}'); // これは成功
console.log(x.age.toFixed()); // ageはundefined → TypeError
} catch (e) {
console.log('エラーが起きました:', e.message); // ここに来る
}
console.log('プログラムはまだ動いています'); // 止まらない
JavaScript- ポイント:
tryの中でエラーが起きると、残りは実行されずにcatchへジャンプします。
例題で理解する
例題1: ユーザー入力の安全確認
- 狙い: 数字だけ受け取りたい。文字が混じっていたら丁寧に案内する。
function toTwoDecimal(input) {
try {
const num = Number(input);
if (Number.isNaN(num)) {
throw new Error('数字を入力してください'); // 自分でエラーを投げる
}
return num.toFixed(2); // 例: 3 → "3.00"
} catch (e) {
return `入力エラー: ${e.message}`;
}
}
console.log(toTwoDecimal('3')); // "3.00"
console.log(toTwoDecimal('3.1415')); // "3.14"
console.log(toTwoDecimal('abc')); // "入力エラー: 数字を入力してください"
JavaScript- 学び:
throw new Error(...)で「意図的なエラー」を作ると、処理を安全に中断できます。
例題2: エラーの種類で分けて対応
- 狙い: 原因に合わせてメッセージや復旧策を変える。
function processValue(value) {
try {
// RangeErrorの例(基数は2〜36)
const s = (100).toString(value); // valueが範囲外だとRangeError
// TypeErrorの例
return s.toFixed(0); // sは文字列なのでTypeError
} catch (e) {
if (e instanceof RangeError) {
return '範囲外の値です(2〜36で指定してください)';
} else if (e instanceof TypeError) {
return '型の問題です(文字列にtoFixedは使えません)';
} else {
return `想定外のエラー: ${e.message}`;
}
}
}
console.log(processValue(10)); // TypeError対応メッセージ
console.log(processValue(100)); // RangeError対応メッセージ
JavaScript- 学び:
instanceofでエラーの種類を判定すると、原因別に分かりやすく対応できます。
例題3: ネット通信の失敗を吸収
- 狙い: 通信が失敗してもアプリが落ちないようにする。再試行や代替値を返す。
async function fetchUser() {
try {
const res = await fetch('https://example.com/user'); // ネットワークで失敗する可能性
if (!res.ok) throw new Error(`HTTPエラー: ${res.status}`);
return await res.json();
} catch (e) {
// ログ+代替値
console.warn('取得に失敗:', e.message);
return { name: 'ゲスト', plan: 'free' }; // フォールバック
}
}
fetchUser().then(user => console.log(user));
JavaScript- 学び: 非同期処理でも
try...catchは使える。失敗時に「代替の結果」を返すのは実用的。
finallyで後片付け
- 役割: エラーがあってもなくても最後に必ず実行される「後片付け用」。
- 典型例: ローディング表示の終了、ファイル・接続のクローズなど。
let loading = true;
try {
// 重い処理
JSON.parse('{"ok": true}');
} catch (e) {
console.error('失敗:', e.message);
} finally {
loading = false; // ここは必ず実行される
console.log('ローディング終了');
}
JavaScriptよくあるつまずきポイントと対策
- エラーを握りつぶさない:
ただcatchして何もしないのは危険。- 対策: ログを残す、ユーザーにわかりやすいメッセージを出す、必要なら再スローする。
try {
// ...
} catch (e) {
console.error(e); // ログ
throw e; // 上位に任せる(必要なときだけ)
}
JavaScript- SyntaxErrorはcatchできないことがある:
コード自体が壊れていると、そもそも実行が始まらない。- 対策: エディタのLintやフォーマッタで事前に防ぐ。
- 非同期の例外:
Promiseの中のエラーは、awaitでtry...catchするか、.catch()を忘れない。- 対策:
async/await+try...catchを基本形に。
- 対策:
実務での使い分けのコツ
- まずは広く受け止める: クリティカルな箇所は
try...catchで全体を守る。 - 原因別に丁寧にする: ユーザー入力、外部API、ファイル処理などは種類別対応が効果的。
- 後片付けはfinally: ローディング解除、リソース解放は
finallyに置く。 - 意図的なエラー発生: バリデーション失敗など「期待外れ」は
throw new Error('わかりやすい日本語')。
まとめと次の一歩
- 要点: 「例外は悪者じゃない」「
try...catchで安全に運ぶ」「種類別で原因に合った対応をする」。 - 練習課題:
- 入力バリデーション: 年齢入力フォームで、数字以外ならメッセージを表示。
- APIフォールバック: 通信失敗時にキャッシュや固定データを返す。
- finally活用: ボタン押下で処理中表示→成功/失敗に関係なく必ず終了。
