【JavaScript入門】try-catchによる例外処理でエラーを防ぐ

  • 2025.11.28
       
【JavaScript入門】try-catchによる例外処理でエラーを防ぐ

プログラミングを実行する上で、エラーは切っても切り離せない要素の1つとなります。
エラーが発生するとプログラミングの実行が停止されてしまうため、本来であれば1つもエラーが起きないように作成できるのが1番の理想となりますが、現実には予期しないエラーが発生してしまうことはままあります。

その際に、エラーを安全に回避して、プログラムを止めることなく続行できるようにする方法があります。
それが、例外処理です。

今回の記事では、JavaScriptで例外処理を扱う方法の1つである try…catch文について解説していきたいと思います。
基本的な内容から応用方法、使用する上での注意点などをまとめて解説していきますので、ぜひ参考にしてみてください。

try-catch文とは?

try…catch文は、例外処理を記述する際に使用する構文です。

通常、プログラムの実行中に何かしらのエラーが発生すると、その段階でプログラムの実行は停止されます。
ですが、実際に開発をしていると、エラー発生時にプログラムを停止させることなく次の処理に移行させたいケースは多々出てきます。

try…catch文を使用して例外処理を記述すると、エラー発生時にプログラムが停止する代わりに、記述した処理内容が実行されます。
意図しない動作によってエラーが発生しても、安全に処理を回避させることができるため、プログラムを実行する上で重要な機能となります。

try-catch文の使い方

try…catch文の詳しい使い方について、順に確認していきましょう。

基本構文

まずは、基本構文から解説していきます。

try…catch文を使用する際は、以下のような構文で記述します。

【基本構文】

try {
    //エラーをキャッチしたい処理内容
} catch( error ) {
    //上記の処理でエラーが発生した場合に実行する処理
}

エラーが発生した際に回避させたい処理を try{} で囲み、実際にエラーが発生した場合に実行する回避処理を catch{} で囲んで記述します。

以下の簡単なサンプルで、エラーが実際に発生した場合の動きを見てみましょう。

【サンプルコード】

try {   
    const result = num * 100;
    
    console.log(result);

} catch(error) {

    console.error(error.message);
}

console.log("実行完了");

【実行結果】

num is not defined
実行完了

上記のサンプルでは、未宣言の変数を使用しようとしているため、エラーが発生します。
例外処理を実装していない場合、エラーが発生した段階で処理が止まるため 「実行完了」 のログが表示されませんが、try…catch文を使うことで処理が継続され、コンソールに表示されるようになっています。

また、catchブロックの引数には Errorオブジェクトが渡されるため、messageプロパティを使用してエラーメッセージを取得することが可能です。
上記サンプルのように、エラーが発生した際にコンソールにメッセージを表示することで、動作の確認時に詳細を把握しやすくなるメリットがあります。

throwで強制的に例外を投げる

JavaScriptでは、throw文を使用することで意図的に例外を発生させることができます。
特定の条件下において、ブロック内の処理を停止し次の処理の移行させたい場合などに活用可能です。

以下のサンプルコードで実際の動きを見てみましょう。

【サンプルコード】

try {

    const sampleArray = [1, 5, 3, 12, 8];

    sampleArray.forEach(num => {

         if(num > 10){
             throw new Error("10より大きい数値です");
         }else{
             console.log(num);
         }      
    });

} catch(error) {

    console.error(error.message);
}

【実行結果】

1
5
3
10より大きい数値です

上記のサンプルコードでは、配列内の要素の値が10より大きい場合に例外を投げるよう記述しています。
実行結果を見てみると、4つ目の要素の値が10よりも大きいため、その段階でブロック内の処理が中断され、例外処理が実行されているのが分かるかと思います。

throw文を使用して例外を発生させる場合は、catchブロックの引数に渡す値を任意に指定することができます。
文字列や数値なども指定可能ですが、スタックトレース(関数などの呼び出し履歴)が取得できず、問題の発生箇所の特定が困難となってしまうため、基本的には Errorオブジェクトを渡すのが一般的です。

エラーオブジェクトの種類について

JavaScriptには、Errorオブジェクトのサブクラスであるエラー型が何種類か存在します。

例えば、変数や引数などのデータ型に関するエラーや、数値などを扱う際の有効範囲に関するエラーなど、それぞれのケースに対応するエラー型が既存で用意されています。
try…catch文のブロック内で意図的でない例外が発生した際に、catchブロックの引数に渡される Errorオブジェクトは、厳密にはこのエラー型のいずれかとなります。

以下に、代表的なエラー型をいくつか紹介したいと思います。

【RangeError】

特定の処理に対して、有効な値の範囲外にある数値を指定した場合に発生するエラーです。
主に、関数などの引数に値を渡す際に発生します。

【サンプルコード】

 // Arrayコンストラクタで不正な長さの配列を作成しようとする
const sampleArray = new Array(-1);

【ReferenceError】

存在しない、またはアクセスできない変数や関数を参照しようとした場合に発生するエラーです。
スペルミスなどで存在しない変数にアクセスしようとしたり、ブロックスコープにブロック外からアクセスしようとした際に発生します。

【サンプルコード】

 // 宣言されていない変数 sample を参照
console.log(sample);

【SyntaxError】

実行するコードの構文にミスがある場合に発生するエラーです。
メソッドを記述する際に括弧の閉じ忘れがあったりなど、決められた文法に沿わないコードがあると発生します。

SyntaxErrorに関しては、エラーが検知されるタイミングの関係上、基本的には try…catch文でキャッチすることはありません。
ただし、throw文で catchブロックに渡す値を指定する際に、SyntaxErrorを使用することは可能です。

【サンプルコード】

 // ) が余分に記述されている
console.log("Hello"));

【TypeError】

特定の処理に対して、使用する値が期待するデータ型でなかった場合に発生するエラーです。
対象のデータ型にないプロパティやメソッドを使おうとしたり、関数でないものを関数として呼び出したりした際に発生します。

【サンプルコード】

const sampleNum = 10;
// 数値型にsliceメソッドはないためエラーとなる
const result = sampleNum.slice(2);

【URIError】

encodeURI や decodeURI などの関数で、不正なパラメータが使用された場合に発生するエラーです。
エンコード、もしくはデコードが不可能な値が引数に入力された際に発生します。

【サンプルコード】

// 不完全なパーセントエンコーディング
decodeURI('%');

try-catch文の活用法

try…catch文の基本的な使用方法は上述した通りですが、その他にもいくつかの便利な機能が存在します。
順に確認していきましょう。

複数のエラーをキャッチする

Promise.anyメソッドを実行した場合など、処理内容によっては複数のエラーが発生するケースも存在します。
その際に活用されるのが、AggregateError オブジェクトです。

AggregateErrorは、複数のエラーを1つの値としてまとめることができます。

【サンプルコード】

try {
    const errors = [new Error("error1"), new Error("error2")];
    throw new AggregateError(errors, "sampleError");
    
} catch(error) {
    console.log(error.message); // sampleError
    console.log(error.errors); // [Error: error1, Error: error2]
}

また、処理内容によっては、発生するエラーの種類にいくつかの候補がある場合もあります。
エラーの種類によって、実行する例外処理を条件分けしたい場合には、instanceof演算子を使用して型チェックを行いましょう。

【サンプルコード】

try {
    const sampleNum = 10;
    
    sampleNum();
        
} catch(e) {

    if (e instanceof TypeError) {
        // TypeErrorの場合の処理
        console.error("TypeError:", e.message);
        
    } else if (e instanceof ReferenceError) {
        // ReferenceErrorの場合の処理
        console.error("ReferenceError:", e.message);
        
    } else {
        // その他のエラーの場合の処理
        console.error("予期せぬエラーが発生しました:", e);
    }
}

【実行結果】

TypeError: sampleNum is not a function

finally文で必ず実行する処理を記述する

try…catch文は、例外が発生した場合には tryブロックの処理が中断され、発生しなかった場合には catchブロックの処理がスルーされます。
そうした処理結果に関わらず、必ず実行させたい処理がある場合に役立つのが、finally文です。

【サンプルコード】

try {
    const sampleNum = 10;
    sampleNum();

    console.log("実行されません");
        
} catch(e) {
    console.error(e.message);

} finally {
    console.log("必ず実行されます");
}

【実行結果】

sampleNum is not a function
必ず実行されます

必要となるケースはそこまで多くはありませんが、覚えておくと便利な機能です。

try-catchのエラーオブジェクト

既に上述したように、try…catch文での例外処理には Errorオブジェクトが欠かせません。

Errorオブジェクトには、先ほどのサンプルコードで使用した messageプロパティの他に、エラー内容の詳細確認に活用できるいくつかのプロパティが存在します。
それらを使用する方法についても紹介します。

stackプロパティでスタックトレースを行う

Errorオブジェクトには、エラーが発生した箇所や原因を詳しく知るのに役立つプロパティがいくつかあります。
その中の1つが、stackプロパティです。

stackプロパティは、エラーの発生箇所を含むスタックトレースを取得することができるプロパティです。
これにより、どの処理が原因でエラーが発生したのかを読み取ることができます。

【サンプルコード】

try {
    const sampleNum = 10;  
    sampleNum();
        
} catch(e) {   
    console.error(e.stack);
}

【実行結果】

TypeError: sampleNum is not a function
    at Object.<anonymous> (/tmp/main.js:4:5)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49

stackプロパティでは、エラータイプなどを示すエラーメッセージに加えて、エラー発生から直近までの実行内容の履歴を取得することができます。
履歴には、処理が実行されたオブジェクトや関数と、記述されているファイルや行などの情報が表示されます。
これらの内容を確認することで、エラーが発生した具体的な処理内容や場所を特定することができます。

また、エラーが発生した箇所のファイル名や行番号などを個別に確認したい場合は、fileNameプロパティとlineNumberプロパティで取得可能です。

【サンプルコード】

try {
    const sampleNum = 10;  
    sampleNum();
        
} catch(e) {   
    console.error(e.message);
    console.error(e.fileName);
    console.error(e.lineNumber);
}

【実行結果】

sampleNum is not a function
/tmp/main.js
4

ただし、これらのプロパティはいずれも非標準であるため、ブラウザーの対応が限られています。
また、標準化される予定も今のところなく、使用できなくなってしまう可能性も少なからず残されています。

使用時の注意点として、本番環境での使用は推奨されていないので、あくまでデバッグ時の機能として留めておくようにしましょう。

エラー処理を関数化する

エラー発生による例外処理を行う際は、ほぼ必ずといった頻度でエラー内容の表示を行うかと思います。
そのため、それぞれの処理で独立する内容を除いて、エラー表示などの共通処理は関数化しておくと効率よく運用できます。

例えば、先ほど紹介したプロパティなどを活用して、独自にエラーメッセージを作成することができます。

【サンプルコード】

function showError(e) {

    let errMsg = `【 エラー:${e.message} 】\n`;
    
    if (e.fileName && e.lineNumber) {
        errMsg += "ファイル名:" + e.fileName + "、 行番号:" + e.lineNumber + "\n";
    }
 
    if (e.stack) {
        errMsg += "---- スタックトレース: ----\n";
        errMsg += e.stack + "\n";
        errMsg += "--------------------------\n";
    }
 
    console.error(errMsg);
}

try {
    const sampleNum = 10;  
    sampleNum();
        
} catch(e) {   
    showError(e);
}

【実行結果】

【 エラー:sampleNum is not a function 】
ファイル名:/tmp/main.js、 行番号:21
---- スタックトレース: ----
TypeError: sampleNum is not a function
    at Object.<anonymous> (/tmp/main.js:21:5)
    at Module._compile (node:internal/modules/cjs/loader:1376:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1435:10)
    at Module.load (node:internal/modules/cjs/loader:1207:32)
    at Module._load (node:internal/modules/cjs/loader:1023:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:135:12)
    at node:internal/main/run_main_module:28:49
--------------------------

これらの処理を関数化しておくことで、簡単に独自メッセージを表示させることができます。
多くのログの中にエラーメッセージが紛れていると見づらい場合も多く、確認するのに手間が生じてしまうこともあるため、見やすいようにカスタムするのは1つの手です。

try-catch文の注意点

try…catch文は、先ほど解説した一部のプロパティの他にも、使用する上で注意しなければならない重要な点がいくつか存在します。

それぞれのポイントについて、一緒に確認していきましょう。

非同期処理では try-catch文が効かない

例外処理に活用されている try…catch文ですが、非同期処理で発生したエラーについてはキャッチすることができません。
例えば、以下のような例です。

【サンプルコード】

try {
  setTimeout(() => {
    throw new Error('非同期エラー');
  }, 3000);
} catch (e) {
  console.error(e.message); // この処理は呼ばれない
}

上記のサンプルの場合、throw文で例外を投げる処理の実行タイミングが setTimeout によって後ろにずらされているため、コードが実行される段階でプログラミング全体の処理は既に tryブロックを抜けた後の状態となっています。
try…catch文では、スコープが tryブロック内にある間のエラーしかキャッチすることができないため、非同期処理によってエラーが発生しても catchブロックの処理は実行されずに終わってしまいます。

非同期処理の場合は、try…catch文の代わりに Promiseの catchメソッドを使用してエラーをキャッチするか、もしくは async/await と組み合わせて try…catch文を使用するようにしましょう。

【サンプルコード】

// Promise.catch の場合
new Promise((_, reject) => {
  setTimeout(() => {
    reject(new Error('非同期エラー'));
  }, 3000);

}).catch((e) => {
    console.error(e.message);
});

// async/await の場合
async function sample() {
  try {
    const res = await fetch('/sample/data');
    const data = await res.json();
    console.log('取得成功:', data);
  } catch (e) {
    console.error('データ取得に失敗:', e.message);
  }
}

パフォーマンスを下げずにtry-catch文を使用する

try…catch文は、いざという時のエラー回避に役立つ便利な構文ですが、処理時間が遅いというデメリットがあります。
基本的には、try…catch文を使用していたというだけで、プログラムの実行に大きく影響が出るほどエラーが頻繁に発生することはあまりありませんが、必要以上に使用とパフォーマンスの低下に繋がってしまう恐れがあります。

試しに以下のサンプルで、繰り返し処理を実行した場合にかかる時間を計測してみましょう。

【サンプルコード】

function funcTryCatch() {
    try {
        throw new Error("message");
    } catch(err) {
        return err.message;
    }
    return true;
}

function measure1() {
    console.time(1);
    for (let i=0;i<100000;i++) funcTryCatch();
    console.timeEnd(1);
}

measure1();

【実行結果】

1: 3.264s

この結果を見るだけでも、全ての処理を終えるのにかなりの時間がかかっていることが分かります。

こうしたコードの改善策として、if 文を使用した条件分けなどが挙げられます。
そこで、実際に上記のサンプルを if 文で代替した場合の結果と見比べてみましょう。

【サンプルコード】

function funcIf() {
    let message;

    if (message) {
        return message;
    }
    return true;
}

function measure2() {
    console.time(2);
    for (let i=0;i<100000;i++) funcIf();
    console.timeEnd(2);
}

measure2();

【実行結果】

2: 17.338ms

先ほどの結果と比較して、処理にかかる時間が大幅に削減されているのが分かりますね。
このように、try…catch文の使用頻度などによっては、プログラミング全体のパフォーマンスに大きく差が出てしまう場合があります。

コードを記述する際は、本当に try…catch文が必要かどうか、他の案で代替可能であるかなどを吟味した上で使用するようにしましょう。

まとめ

いかがでしたか?今回は、JavaScriptで try…catch文を使用して例外処理を行う方法について解説しました。

プログラムを安全に実行するために、例外処理は必ず必要となってくる重要な機能です。
上述したように、プログラムのパフォーマンスに影響が出やすい機能でもあるため、使い所の見極めが必要となる構文ではありますが、使用することによって得られる恩恵はかなり大きいと言えます。

プログラムを安全に運用するためにも、使い方をしっかりと覚えて開発に役立てていきましょう。

JavaScriptの勉強方法は?

書籍やインターネットで学習する方法があります。昨今では、YouTubeなどの動画サイトやエンジニアのコミュニティサイトなども充実していて多くの情報が手に入ります。
そして、より効率的に知識・スキルを習得するには、知識をつけながら実際に手を動かしてみるなど、インプットとアウトプットを繰り返していくことが重要です。特に独学の場合は、有識者に質問ができたりフィードバックをもらえるような環境があると、理解度が深まるでしょう。

ただ、JavaScriptに限らず、ITスキルを身につける際、どうしても課題にぶつかってしまうことはありますよね。特に独学だと、わからない部分をプロに質問できる機会を確保しにくく、モチベーションが続きにくいという側面があります。独学でモチベーションを維持する自信がない人にはプログラミングスクールという手もあります。費用は掛かりますが、その分スキルを身につけやすいです。しっかりと知識・スキルを習得して実践に活かしたいという人はプログラミングスクールがおすすめです。

プログラミングスクールならテックマニアがおすすめ!

ITスキル需要の高まりとともにプログラミングスクールも増えました。しかし、どのスクールに通うべきか迷ってしまう人もいるでしょう。そんな方にはテックマニアをおすすめします!これまで多くのITエンジニアを育成・輩出してきたテックマニアでもプログラミングスクールを開講しています。

<テックマニアの特徴>
・たしかな育成実績と親身な教育 ~セカンドキャリアを全力支援~
・講師が現役エンジニア ~“本当”の開発ノウハウを直に学べる~
・専属講師が学習を徹底サポート ~「わからない」を徹底解決~
・実務ベースでスキルを習得 ~実践的な凝縮カリキュラム~

このような特徴を持つテックマニアはITエンジニアのスタートラインとして最適です。
話を聞きたい・詳しく知りたいという方はこちらからお気軽にお問い合わせください。

     

Programmingカテゴリの最新記事