例外(エラー)って何?
プログラム実行中に「想定できない問題」が起きると、JavaScript は例外(Error オブジェクト)を投げます。例:存在しない変数にアクセスした、数値の扱いを間違えた、JSON が壊れている、など。例外を放置するとプログラムがそこで止まってしまうので、try…catch で受け止めて安全に処理します。
基本の書き方(復習)
try {
// 問題が起きるかもしれない処理
} catch (e) {
// 例外が投げられたときの処理(eは例外オブジェクト)
} finally {
// (任意)例外が起きても起きなくても必ず実行される処理
}
JavaScript例外の「種類」を使い分ける理由
エラーには種類(クラス)があり、代表的なものは:
TypeError:型が合っていない操作(例:undefinedのプロパティを読む)ReferenceError:存在しない変数を参照したRangeError:数値の範囲が不正(toFixedの桁数が大きすぎる等)SyntaxError:コード自体の構文が間違っている(evalやJSON.parseで発生しやすい)Error:上のどれにも当てはまらない一般的なエラー
種類ごとに処理を変えると「何が原因か」に応じた適切な対応(ログ出力、ユーザー向けメッセージ、リトライなど)ができます。
種類の判定には instanceof を使います:
if (e instanceof TypeError) { ... }
JavaScript実例1 — toFixed の例(RangeError / TypeError が出る場面)
説明:Number.prototype.toFixed(digits) は数値を指定桁で丸めて文字列にするメソッド。引数 digits が大きすぎると RangeError、対象が数値でないと TypeError が起きることがある。
function formatNumber(value, digits) {
try {
return Number(value).toFixed(digits);
} catch (e) {
if (e instanceof RangeError) {
console.error("桁数が大きすぎます:", e.message);
return Number(value).toFixed(2); // フォールバック
} else if (e instanceof TypeError) {
console.error("数値ではありません:", e.message);
return "—"; // 表示用の代替
} else {
console.error("予期せぬエラー:", e);
throw e; // 再送出(呼び出し元に任せる)
}
} finally {
// ここはログや計測コード置き場にできる
// console.log("formatNumber 実行終了");
}
}
console.log(formatNumber(1.2345, 2)); // "1.23"
console.log(formatNumber("abc", 2)); // エラー → "—"
console.log(formatNumber(1.23, 1000)); // RangeError → フォールバックで "1.23"
JavaScriptポイント:
- 特定の型のエラー(
RangeError/TypeError)に応じてログや代替処理を行っている。 - 想定外のエラーは
throw eして上位に任せることもある(無理に握りつぶさない)。
実例2 — JSON.parse と SyntaxError
説明:JSON.parse に壊れた JSON を渡すと SyntaxError が出ます。外部データを扱うときは必ず try…catch で保護しましょう。
function safeParse(jsonStr) {
try {
return JSON.parse(jsonStr);
} catch (e) {
if (e instanceof SyntaxError) {
console.warn("JSON の形式が不正です:", e.message);
return null; // 失敗を示す
} else {
throw e;
}
}
}
console.log(safeParse('{"a":1}')); // { a: 1 }
console.log(safeParse('{a:1}')); // null (警告ログ)
JavaScriptポイント:
- 外部ソースを直接
JSON.parseするのは危険 → 失敗に備える。
実例3 — undefined のプロパティ参照(TypeError)
説明:オブジェクトが undefined のときに .prop を読むと TypeError になります。アクセス前に存在チェックするのが基本ですが、どうしても一連の処理でまとめて捕まえたい場合は try…catch が役に立ちます。
function getNestedValue(obj) {
try {
// ここで obj が undefined だと TypeError になる
return obj.child.value;
} catch (e) {
if (e instanceof TypeError) {
console.error("オブジェクトが期待どおりではありません:", e.message);
return null;
} else {
throw e;
}
}
}
console.log(getNestedValue({ child: { value: 42 } })); // 42
console.log(getNestedValue(undefined)); // null(ログ出力)
JavaScript※ 実務では optional chaining(obj?.child?.value)を使う方が安全で簡潔です。
カスタムエラーの作り方(明確に区別したいとき)
自分でエラーの種類を作れば、より分かりやすくハンドリングできます。
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = "ValidationError";
}
}
function validateUser(user) {
if (!user.name) throw new ValidationError("名前が必要です");
if (typeof user.age !== "number") throw new ValidationError("年齢は数値である必要があります");
return true;
}
try {
validateUser({ age: "twelve" });
} catch (e) {
if (e instanceof ValidationError) {
console.warn("入力エラー:", e.message);
} else {
throw e;
}
}
JavaScript良い書き方・悪い書き方の例(初心者が陥りやすい落とし穴)
良い:特定のエラーに対して具体的な対処を行う
try {
// 処理
} catch (e) {
if (e instanceof SyntaxError) {
// 再読み込み、ユーザーへ通知など
} else {
throw e;
}
}
JavaScript悪い:すべてを握りつぶして原因を隠す(デバッグ不能に)
try {
// 処理
} catch (e) {
// なにもログせずに無視 → NG
}
JavaScript良い:ログを残して、ユーザーにはやさしいメッセージを出す
catch (e) {
console.error(e); // 開発者向け
showUserMessage("予期せぬエラーが発生しました。しばらく経ってからお試しください。");
}
JavaScript練習問題(初心者向け)—— 解答・解説付き
問題1
toFixed を使って、入力値を指定桁で丸めて返す関数 safeToFixed(value, digits) を作りなさい。次の場合に備えて処理を分けること:
digitsが負、または 100 を超える →RangeErrorとして扱い、nullを返す。valueが数値に変換できない →TypeErrorとして扱い、nullを返す。
解答例
function safeToFixed(value, digits) {
try {
// digits の範囲チェック(手動でチェックしてエラーを投げる)
if (typeof digits !== "number" || digits < 0 || digits > 100) {
throw new RangeError("digits は 0〜100 の整数でなければなりません");
}
const num = Number(value);
if (Number.isNaN(num)) throw new TypeError("value は数値に変換できません");
return num.toFixed(digits);
} catch (e) {
if (e instanceof RangeError || e instanceof TypeError) {
console.warn(e.message);
return null;
}
throw e;
}
}
JavaScript解説
toFixed自体がRangeErrorを出す場面もあるが、ここでは事前にチェックして分かりやすいエラーメッセージを投げている。Number.isNaN(num)で数値変換失敗を検出してTypeErrorを投げる。
問題2
外部から受け取った JSON 文字列をオブジェクトに変換する parseUser(jsonStr) を作る。次を満たすこと:
- JSON が不正なら
nullを返す(SyntaxErrorを想定)。 - JSON が正しくても
nameプロパティがなければValidationError(カスタム)として扱い、nullを返す。
解答例
class ValidationError extends Error { constructor(msg) { super(msg); this.name = "ValidationError"; } }
function parseUser(jsonStr) {
try {
const obj = JSON.parse(jsonStr);
if (!obj.name) throw new ValidationError("name が必要です");
return obj;
} catch (e) {
if (e instanceof SyntaxError) {
console.warn("JSON の形式不正:", e.message);
return null;
} else if (e instanceof ValidationError) {
console.warn("データ検証エラー:", e.message);
return null;
} else {
throw e;
}
}
}
JavaScript解説
JSON.parseのSyntaxErrorと自分で投げたValidationErrorを分けて処理。- どちらも呼び出し元に
nullを返して「失敗」を分かりやすくしている。
問題3(改善問題)
次のコードは何が良くない? 改善案を書きなさい。
try {
doSomething(); // 何かの処理
} catch (e) {
// ただ無視している
}
JavaScript模範解答(改善点)
- エラーを丸ごと無視していると、バグの原因が分からなくなる。最低でもログ出力すべき。
- ユーザーにわかりやすいメッセージを表示するか、想定できるエラーだけを捕まえて処理する。
try {
doSomething();
} catch (e) {
console.error("doSomething でエラー:", e);
showUserMessage("処理に失敗しました。ページを再読み込みしてください。");
// 必要なら throw e; で再送出して上位で処理させる
}
JavaScript実務でのベストプラクティス(初心者向けまとめ)
- すべてを握りつぶさない:原因追跡のために
console.errorなどでログを残す。 - 種類ごとの処理:
instanceofやカスタムエラーで分ける。 - ユーザーにはやさしく、開発者には詳しく:ログは詳しく、ユーザー向けメッセージは簡潔に。
- 例外は仕様の一部として扱う:外部入力や非同期処理は例外が起きる前提で設計する。
- 非同期処理にも対応:
async/awaitの中でもtry…catchを使う。例:
async function fetchData() {
try {
const res = await fetch("/api/data");
const data = await res.json();
return data;
} catch (e) {
console.error("取得失敗:", e);
return null;
}
}
JavaScript