【JavaScript】例外処理

# 概要
JavaScriptを学習、理解を深めるため「[JavaScript Primer 迷わないための入門書](https://jsprimer.net/)」を読み、
理解した内容等を記載していく。

「[【JavaScript】JavaScript入門一覧](https://qiita.com/andota05/items/22fae452225b785fd405)」に他の記事をまとめています。

# この記事で理解できること
* JavaScriptにおける例外処理の方法
* try...catch構文、throw文の概要

# try...catch構文
「try...catch」構文には、構成する以下のブロックキーワードが存在する。

* try
* catch
* finally

>**例外(exception)とは**
>想定ができていた(想定内の)エラー
>「例：外部から〇〇を取得する処理だけど、HTTPステータス 403(権限が無かった等で失敗)のレスポンスがあるかもしれない」と想定できていたエラーなど

## ★覚えておこう
try...catch構文では```catch```もしくは```finally```ブロックのいずれかは必須となる。
組み合わせとしては以下3パターンが想定される。
① ```try...catch...finally```
② ```try...catch```(finallyブロック省略)
③ ```try...finally```(catchブロック省略)

## try(ブロック)
* 例外発生が想定される処理は`tryブロック`に記述する。
* tryブロック内で例外が発生した場合
    * それ以降の`tryブロック内の処理`は実行されず`catchブロック`へ処理が移行される。

```js
// ...省略

try {
  // tryブロック：例外発生が想定される処理を記載
  console.log('【tryブロック】処理を開始します】');
  const value = '初期値';
  
  // constで宣言された変数のため例外エラーが発生する
  value = 'constで宣言された変数に再代入';

  // tryブロックでは例外が発生した処理以降は実行されず、catchブロックへ処理が移行する
  console.log('例外発生時この処理含め、以降の処理は実行されない');
  console.log('【tryブロック】処理を終了します');
}

// ...省略
```

## catch(ブロック)

* tryブロックの処理で例外が発生した場合、エラーをキャッチし、`catchブロック`内の処理に移る。
* catchブロック内でのみ参照が可能な`例外の値`を保持する`例外識別子`が存在する(下記、例の`catch (error) {..}`の「error」箇所)

```js
// ...省略

catch (error) { 
  // catchブロック：例外が発生した場合に実行したい処理を記載
  console.log('【catchブロック】処理を開始します');
  console.log(error);
  console.log('【catchブロック】処理を終了します');
}

// ...省略
```

## finally(ブロック)
* `tryブロック`での例外発生有無に関わらず、必ず最後に処理が実行されるブロック。
* catchブロックを省略した場合は、`finallyブロックの処理`を実行後、例外が発生。

```js
finally {
  // finallyブロック：例外発生有無は関係なく一連の処理で最後に行いたい処理を記載
  console.log('【finallyブロック】処理を開始します');
  console.log('一連の処理で最後に行われる処理');
  console.log('【finallyブロック】処理を終了します');
}
```

### 例：一連の処理(関数の場合)
```js
function exceptionSample() {
  console.log('【処理1】を開始します');

  try {
    // tryブロック：例外発生が想定される処理を記載
    console.log('【tryブロック】処理を開始します');
    const value = '初期値を代入';

    // constで宣言された変数のため例外エラーが発生する
    value = 'constで宣言された変数に再代入';

    // tryブロックでは例外が発生した処理以降は実行されず、catchブロックへ処理が移行する
    console.log('例外発生時この処理含め、以降の処理は実行されない');
    console.log('【tryブロック】処理を終了します');
  } catch (error) { 
    // catchブロック：例外が発生した場合に実行したい処理を記載
    console.log('【catchブロック】処理を開始します');

    // キャッチしたエラーの内容を出力
    console.log('キャッチしたerrorの内容を出力')
    console.log(error);

    console.log('【catchブロック】処理を終了します');
  } finally {
    // finallyブロック：例外発生有無は関係なく一連の処理で最後に行いたい処理を記載
    console.log('【finallyブロック】処理を開始します');
    console.log('一連の処理で最後に行われる処理');
    console.log('【finallyブロック】処理を終了します');
  }

  console.log('【処理2】を開始します');
};

exceptionSample();

// => 【処理1】を開始します
// => 【tryブロック】処理を開始します
// => 【catchブロック】処理を開始します
// => キャッチしたerrorの内容を出力
// => TypeError: Assignment to constant variable.
// => 【catchブロック】処理を終了します
// => 【finallyブロック】処理を開始します
// => 一連の処理で最後に行われる処理
// => 【finallyブロック】処理を終了します
// => 【処理2】を開始します
```

# 例外を投げる方法
tryブロックの処理内で結果(の条件)によっては例外とみなしたい場合など、<br>`throw文`を用いて`ユーザー定義(こちらの都合で)`の例外をcatchブロックへ投げることができる。

※throw文を用いて、catchブロックへ処理を移行することを「(catchブロックへ)例外を投げる」と表現されることが多いです。

## throw文の前に...エラーオブジェクト(Error)について
* throw文では例外として`エラーオブジェクト`を投げることが可能。
* エラーオブジェクトはJavaScriptの標準組み込みオブジェクトである、`Errorオブジェクト`をインスタンス化(`new Error()`)することで生成可能。
* 第一引数には`エラーメッセージ`を設定する。
* エラーメッセージは`例外識別子`(下記例では「error」)の`messageプロパティ`で参照可能。

## throw文
* throw文を使用し、`catchブロックに対し例外を投げる。`
* 例外は、`オブジェクト`として投げられる。
* また、あらゆるオブジェクトを例外として投げることができるが、`Errorオブジェクトのインスタンス`を投げることが推奨されている。

### 例：数値を比較し条件を満たさない場合は、throw文で例外を投げる
```exception.js
function exceptionSample() {
  console.log('【処理1】を開始します');

  try {
    // tryブロック：例外発生が想定される処理を記載
    console.log('【tryブロック】処理を開始します');

    const value = -1;

    if (value < 0) {
      throw new Error("0より小さい値なので例外を投げました");
    }

    console.log('【tryブロック】処理を終了します');
  } catch (error) { 
    // catchブロック：例外が発生した場合に実行したい処理を記載
    console.log('【catchブロック】処理を開始します');

    // キャッチしたエラーの内容を出力
    console.log('キャッチしたオブジェクトerrorのメッセージを出力')
    console.log(error.message);

    // tryブロックでは例外が発生した処理以降は実行されず、catchブロックへ処理が移行する
    console.log('【catchブロック】処理を終了します');
  } finally {
    // finallyブロック：例外発生有無は関係なく一連の処理で最後に行いたい処理を記載
    console.log('【finallyブロック】処理を開始します');

    console.log('一連の処理で最後に行われる処理');

    console.log('【finallyブロック】処理を終了します');
  }

  console.log('【処理2】を開始します');
};

exceptionSample();

// => 【処理1】を開始します
// => 【tryブロック】処理を開始します
// => 【catchブロック】処理を開始します
// => キャッチしたerrorの内容を出力
// => Error: 0より小さい値なので例外を投げました
// => 【catchブロック】処理を終了します
// => 【finallyブロック】処理を開始します
// => 一連の処理で最後に行われる処理
// => 【finallyブロック】処理を終了します
// => 【処理2】を開始します
```

## 番外編：try..catch構文で例外処理をしない場合
例外処理をしない場合、例外が発生した時点で処理が終了してしまいます。
例外が発生しうる処理を行う場合は、`try..catch構文`を使用することが得策ですね！

これまでの例では「【処理2】を開始します」というログを出力していましたが、
下記では【処理1】で例外が発生して終了していることが確認できます。

```js
function exceptionSample() {
  console.log('【処理1】を開始します');

  const value = '初期値';
  // ここで例外が発生する
  value = '再代入はできない'

  // 以降の処理は実行されず終了する
  console.log('例外発生時ここ以降の処理は実行されない');
  console.log('【処理2】を開始します');
};

exceptionSample();

// => 【処理1】を開始します
// => ncaught TypeError: Assignment to constant variable...
```