では try…catch…finally を中心に、初心者向けに やさしく、順を追って、たっぷり例題付きで 解説します。読むだけで「実際にコードを書いてデバッグできる」レベルを目指します。
1) まずは仕組みを直感で理解する(超かんたん)
try:エラーが出るかもしれない処理を入れる箱。catch:tryの中でエラー(例外)が起きたときに実行される箱。エラー情報を受け取れる。finally:例外の有無に関係なく 必ず実行 される箱。ファイルを閉じる、タイマーをクリアする、UIを戻す、などに使う。
図にすると:
実行開始
└─ try の処理実行
├─ 正常なら → finally 実行 → 続行
└─ エラーなら → catch 実行 → finally 実行 → 続行
2) 基本の書き方(コードで確認)
try {
// エラーが出るかもしれない処理
} catch (e) {
// エラーが発生したときの処理(e にエラー情報が入る)
} finally {
// 例外が起きても起きなくても「必ず」実行される処理
}
JavaScriptcatch の (e) は省略可能(ただしエラー情報を使わないとき)。
try {
throw new Error('問題発生');
} catch {
console.log('エラー発生!');
}
JavaScript3) 具体例 → ステップで解説
例1:数値の足し算(簡単)
function sum(a, b) {
try {
return a + b;
} catch (e) {
console.error('エラー:', e);
return null;
} finally {
console.log('終わりました(finally)');
}
}
console.log(sum(2, 3)); // 5 と表示、finally 実行
JavaScriptポイント:
- 正常時でも
finallyは実行される。 try内でreturnがあっても、finallyは その前に 実行される(詳しくは後述)。
例2:型の不整合でエラーを起こす(意図的にcatchを使う)
function safeDivide(a, b) {
try {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('数値を渡してください');
}
if (b === 0) {
throw new Error('0 で割れません');
}
return a / b;
} catch (e) {
console.error('caught:', e.message);
return null;
} finally {
console.log('リソース解放などの後処理を実行');
}
}
console.log(safeDivide(10, 2)); // 5
console.log(safeDivide(10, 0)); // null, エラーメッセージ表示
console.log(safeDivide('x', 2)); // null, TypeError
JavaScriptポイント:
throwで自分から例外を発生させられる(エラーを明示するのに便利)。catchでe.messageやe.name、e.stackを使える。
4) finally と return の注意(初心者がハマりやすい)
try または catch に return があっても、finally はその前に必ず実行されます。ただし finally 自体が値を返すと元の return を上書きしてしまう ので注意。
function test() {
try {
return 'tryの値';
} finally {
return 'finallyの値';
}
}
console.log(test()); // "finallyの値"
JavaScript→ finally 内で return や throw をしないのが鉄則。副作用(ログ、リソース解放)に使うのが適切。
5) 例外オブジェクト(Error)の使い方とカスタム例外
エラーは new Error('メッセージ') で作ります。組み込みの TypeError や RangeError もあります。必要なら自分でカスタムエラーを作れます。
class MyAppError extends Error {
constructor(message) {
super(message);
this.name = 'MyAppError';
}
}
try {
throw new MyAppError('ユーザー定義の問題');
} catch (e) {
console.log(e.name, e.message); // MyAppError ユーザー定義の問題
console.log(e.stack); // スタックトレース
}
JavaScript6) 非同期(Promise / async/await)での例外処理
同期コードと同じパターンで考えられますが、注意点あり。
Promise の場合
fetch('/api/data')
.then(res => res.json())
.catch(err => {
// ネットワークや JSON 解析の失敗をここで処理
console.error('fetch error:', err);
});
JavaScriptasync/await の場合(同期と同じ try/catch が使える)
async function load() {
try {
const res = await fetch('/api/data');
const data = await res.json();
return data;
} catch (e) {
console.error('読み込み失敗:', e);
return null;
} finally {
console.log('fetch 完了(成功/失敗どちらでも)');
}
}
JavaScriptポイント:
awaitの先で例外(Promise の reject)が起きるとcatchに飛ぶ。- 非同期関数の内部で
try/catchを使うとエラー処理が分かりやすくなる。
7) スタックトレース(e.stack)の見方 — デバッグの基礎
catch (e) { console.error(e.stack); } で得られる文字列は、どの関数でどの行で例外が起きたかを示します。ブラウザ・Node でフォーマットはやや違いますが、基本的には上から順に「発生場所 → 呼び出し元 → …」という流れです。
デバッグ方法:
console.error(e)/console.error(e.stack)を出す。- ブラウザ開発ツール(DevTools)の Console に表示されるスタックをクリックすると該当ソースへジャンプできる。
debugger;をコードに書く(あるいは DevTools のブレークポイント)で、例外発生前後をステップ実行可能。
8) よくあるよくある間違い(初心者がやりがち)
finallyにreturnを書いて後の値を上書きしてしまう。- 無理にすべてのエラーを握りつぶしてしまう(
catch内で何もせず silent にする)。→ ログは残すべき。 - 非同期の Promise を返さない
async関数でエラーを外に出してしまう(awaitを忘れてtry/catchが効かないケース)。
// NGパターン
try {
fetch('/api'); // await を忘れた → ここでは例外は捕まらない
} catch (e) {
// ここは実行されないことが多い
}
JavaScript→ await fetch(...) あるいは fetch(...).catch(...) を使う。
9) 練習問題
下に問題と解答を用意しました。まずは自分でコードを実行してみてから答えを見てください。
問題1
parseInt を使って文字列から数を取り出す関数 toNumber(str) を作る。もし str が数字に変換できない場合は throw new Error('数値ではありません') して、それを呼び出し元で catch して "invalid" を返すようにし、finally で "done" をコンソールに出力すること。
解答1(参考)
function toNumber(str) {
try {
const n = parseInt(str, 10);
if (Number.isNaN(n)) throw new Error('数値ではありません');
return n;
} catch (e) {
return 'invalid';
} finally {
console.log('done');
}
}
console.log(toNumber('123')); // 123 と表示, done
console.log(toNumber('abc')); // invalid と表示, done
JavaScript問題2
非同期関数 fetchJson(url) を作る。fetch して res.json() を返すが、HTTP ステータスが 200 以外なら throw して、それを catch して null を返すようにし、finally で "fetch finished" を出力すること。(擬似コードで OK)
解答2(参考)
async function fetchJson(url) {
try {
const res = await fetch(url);
if (!res.ok) throw new Error('HTTP error ' + res.status);
const data = await res.json();
return data;
} catch (e) {
console.error(e);
return null;
} finally {
console.log('fetch finished');
}
}
JavaScript10) デバッグ実践ワンポイント(ブラウザ開発ツール)
- エラーが起きたら Console に出る赤いメッセージをクリック → どのファイルの何行目か分かる。
- Sources(ソース)タブで該当ファイルにブレークポイントを置いてステップ実行。変数の中身を確認できる。
debugger;をコードに入れると、その行で自動的に停止する(DevTools が開いている場合)。- async/await の中で止めたいときはブレークポイントを
awaitの行に置けば、その前後の値を確認できる。 - Source Map がある場合は TypeScript / Babel 等の元のコード(.ts / .jsx)でデバッグできる。
まとめ(覚えておくべきこと)
tryで安全に囲む、catchで「どう処理するか」決める、finallyで「必ずやること」を書く。throwで自分からエラーを投げられる。new Error(...)を基本に。finallyにreturnやthrowを書くと元の挙動が変わるので避ける。- 非同期(Promise / async)でも
try/catchを使える。awaitを忘れない! - 常にエラーはログを残しつつ適切に処理(握りつぶさない)。
