JavaScript / LESSON 10 / JS10

JavaScript:エラー処理(try / catch / throw)

1学習の目的

2基礎解説

やりたいこと書き方意味
エラーを受け止めるtry { } catch (e) { }止まらずに続行できる
内容を読むe.name / e.message種類とメッセージ
自分で出すthrow new Error("理由")不正を呼び出し元に知らせる
必ず実行するfinally { }成功・失敗どちらでも
✅ 覚えるべき重要ポイント
  1. JavaScriptは多くの異常でエラーを出さない10 / 0 は Infinity、Number("abc") は NaN、存在しないキーは undefined。止まらず静かに壊れるのが最大の怖さ。
  2. だから自分で検証して throw する必要がある。if (Number.isNaN(v)) throw new Error("数値ではありません"); のように書く。
  3. よく出るエラー:TypeError(null や undefined のプロパティを読んだ)、ReferenceError(未定義の変数)、SyntaxError(JSON.parse の失敗)。
  4. catch (e) の e はエラーオブジェクトe.message で理由、e instanceof TypeError で種類を判定できる。
  5. finally は成功でも失敗でも必ず実行される。後始末を書く場所で、return があっても実行される。

現場使用例:APIリクエストの失敗、JSONの解析失敗、フォーム入力の検証、CSVの不正行スキップ。外部から来るデータを扱う処理には必ず必要

// JavaScriptはエラーにならないことが多い
console.log(10 / 0);           // Infinity ← 止まらない
console.log(Number("abc"));    // NaN      ← 止まらない

// だから自分で検証して throw する
const parseAmount = (text) => {
  const value = Number(text);
  if (Number.isNaN(value)) {
    throw new Error("数値に変換できません");
  }
  return value;
};

try {
  console.log(parseAmount("100"));   // 100
  console.log(parseAmount("abc"));   // ここで throw される
} catch (e) {
  console.log(`エラー:${e.message}`);
} finally {
  console.log("処理を終了しました");
}

3基本ドリル(10問)

JS10-D01 throw new Error("テストエラー") を try で囲み、catch で「エラー:テストエラー」と出力せよ。 コーディング★☆☆無料
期待される結果

出力 == エラー:テストエラー

ヒント

catch (e) { } の中で e.message を使う。

模範解答
try {
  throw new Error("テストエラー");
} catch (e) {
  console.log(`エラー:${e.message}`);
}
解説

try/catchの最小形。e.message には throw のときに渡した文字列が入る。

JS10-D02 console.log(10 / 0); を実行するとどうなるか。
A. エラーで停止する B. Infinity と表示される C. 0 と表示される D. NaN と表示される
選択★☆☆無料
期待される結果

解答 == B

ヒント

JavaScriptはゼロ除算をエラーにしない。

模範解答
B
解説

Pythonなら ZeroDivisionError で止まるが、JavaScriptは Infinity を返して進む。この「止まらなさ」が原因不明のバグを生む。

JS10-D03 null.foo にアクセスして発生するエラーを catch し、エラーの種類を出力せよ(e.name を使うこと)。 コーディング★☆☆無料
期待される結果

出力 == TypeError

ヒント

try の中で null.foo を書き、catch (e) で e.name を出す。

模範解答
try {
  null.foo;
} catch (e) {
  console.log(e.name);
}
解説

TypeError は最頻出のエラー。「Cannot read properties of null」というメッセージを見たら、null や undefined のものにアクセスしていると考える。

JS10-D04 エラーを受け止めるコードを完成させよ。 穴埋め★☆☆無料
コード
try {
  throw new Error("失敗");
} ____ (e) {
  console.log(e.message);
}
期待される結果

出力 == 失敗

ヒント

「捕まえる」という意味の英単語。

模範解答
catch
解説

catch は投げられたエラーを受け止める。ここが無いとプログラム全体が停止する。

JS10-D05 finally ブロックはいつ実行されるか。
A. エラーが起きたときだけ B. エラーが起きなかったときだけ C. どちらの場合も必ず D. 実行されない
選択★☆☆無料
期待される結果

解答 == C

ヒント

名前のとおり「最後に必ず」。

模範解答
C
解説

成功・失敗にかかわらず実行される。try の中に return があっても finally は実行されるので、後始末の置き場所として確実。

JS10-D06 文字列 "abc" を Number で変換し、NaN なら 「数値に変換できません」と出力せよ(Number.isNaN を使うこと)。 コーディング★★☆無料
期待される結果

出力 == 数値に変換できません

ヒント

Number("abc") は NaN になる。Number.isNaN(値) で判定する。

模範解答
const value = Number("abc");

if (Number.isNaN(value)) {
  console.log("数値に変換できません");
}
解説

NaN は == でも === でも自分自身と一致しないという特殊な値。だから value === NaN では判定できず、Number.isNaN() を使う。

JS10-D07 自分でエラーを発生させるコードを完成させよ。 穴埋め★★☆無料
コード
const check = (n) => {
  if (n < 0) {
    ____ new Error("マイナスは不可");
  }
  return n;
};

try {
  check(-1);
} catch (e) {
  console.log(e.message);
}
期待される結果

出力 == マイナスは不可

ヒント

「投げる」という意味の英単語。

模範解答
throw
解説

throw はその場で関数を抜け、呼び出し元の catch まで飛ぶ。return と違い、途中の処理はすべて中断される。

JS10-D08 Number("abc") の結果はどれか。
A. エラーになる B. 0 C. NaN D. null
選択★★☆無料
期待される結果

解答 == C

ヒント

「数値ではない」を表す特別な値。

模範解答
C
解説

NaN は計算に混ざるとすべてを NaN にする。合計が NaN になったら、どこかで変換に失敗していると疑う。

JS10-D09 values = ["10", "abc", "25"] の各要素を数値に変換して出力せよ。変換できないものは「変換エラー」と出力し、処理は止めないこと コーディング★★☆無料
期待される結果

出力 == 10 / 変換エラー / 25(3行)

ヒント

ループの中に try/catch を入れる。NaN なら throw して catch で受け止める。

模範解答
const values = ["10", "abc", "25"];

for (const v of values) {
  try {
    const n = Number(v);
    if (Number.isNaN(n)) {
      throw new Error("変換エラー");
    }
    console.log(n);
  } catch (e) {
    console.log(e.message);
  }
}
解説

try/catch をループの中に置くのが要点。外に置くと最初の失敗でループごと終わってしまう。1件ずつ守るのが正しい形。

JS10-D10 JSON.parse("{壊れたJSON}") を try で囲み、「解析失敗:SyntaxError」の形式で出力せよ。 コーディング★★☆無料
期待される結果

出力 == 解析失敗:SyntaxError

ヒント

catch (e) の e.name を使う。

模範解答
try {
  JSON.parse("{壊れたJSON}");
} catch (e) {
  console.log(`解析失敗:${e.name}`);
}
解説

JSON.parse は数少ない「ちゃんとエラーを出す」処理。APIの応答が壊れていることは実際にあるので、必ず try で囲む。

4実践シナリオ(5問)

JS10-S01 【安全な割り算】2つの数を受け取り、割り算の結果を返す関数 safeDiv を定義せよ。0で割る場合は null を返すこと。(10, 2)、(10, 0)、(7, 3) の3件について、成功時は「10 ÷ 2 = 5.00」(小数2桁)、失敗時は「10 ÷ 0 = 計算できません」の形式で出力せよ。 コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

JavaScriptは 10/0 でエラーにならず Infinity を返すので、自分で b === 0 を判定する必要がある。

模範解答
const safeDiv = (a, b) => {
  if (b === 0) {
    return null;
  }
  return a / b;
};

for (const [a, b] of [[10, 2], [10, 0], [7, 3]]) {
  const result = safeDiv(a, b);

  if (result === null) {
    console.log(`${a} ÷ ${b} = 計算できません`);
  } else {
    console.log(`${a} ÷ ${b} = ${result.toFixed(2)}`);
  }
}
解説

JavaScriptは0除算でエラーを出さないので、try/catch では捕まえられない。自分で条件を書いて防ぐしかないのがPythonとの大きな違い。

JS10-S02 【不正データを飛ばして集計】raw = ["120", "abc", "85", "", "43"] を整数に変換せよ。変換できないものはスキップし、成功したものだけで集計して3行出力すること。
「変換成功:[120,85,43]」「成功3件 / 失敗2件」「合計:248」
※空文字は Number("") が 0 になるため、空文字も失敗として扱うこと
コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

空文字のチェックを先に入れる。!v で空文字を弾いてから Number.isNaN を見る。配列の表示は JSON.stringify()。

模範解答
const raw = ["120", "abc", "85", "", "43"];

const nums = [];
let failed = 0;

for (const v of raw) {
  try {
    if (!v) {
      throw new Error("空です");
    }
    const n = Number(v);
    if (Number.isNaN(n)) {
      throw new Error("数値ではありません");
    }
    nums.push(n);
  } catch (e) {
    failed++;
  }
}

console.log(`変換成功:${JSON.stringify(nums)}`);
console.log(`成功${nums.length}件 / 失敗${failed}件`);
console.log(`合計:${nums.reduce((s, n) => s + n, 0)}`);
解説

Number("") が 0 になるのがJavaScriptの罠。空欄が0として集計に混ざると、平均値が静かに狂う。NaN チェックだけでは不十分で、空文字も明示的に弾く必要がある。

JS10-S03 【JSONの解析】3つの文字列を JSON.parse で解析し、成功なら「[1] 解析成功:田中」、失敗なら「[2] 解析失敗:SyntaxError」の形式で出力せよ。
'{"name":"田中"}'"{壊れた}"'{"name":"鈴木"}'
コーディング★★☆無料
期待される結果

出力3行が完全一致

ヒント

entries() で番号を振りながら回し、try の中で JSON.parse する。catch では e.name を出す。

模範解答
const inputs = ['{"name":"田中"}', "{壊れた}", '{"name":"鈴木"}'];

for (const [i, text] of inputs.entries()) {
  try {
    const data = JSON.parse(text);
    console.log(`[${i + 1}] 解析成功:${data.name}`);
  } catch (e) {
    console.log(`[${i + 1}] 解析失敗:${e.name}`);
  }
}
解説

APIの応答が必ず正しいJSONとは限らない。サーバーがエラーページのHTMLを返すこともある。JSON.parse は必ず try で囲むのが鉄則。

JS10-S04 【自作エラークラス】Error を継承した StockError を定義せよ(name を "StockError" にすること)。商品名と在庫を持つ出荷関数 ship(name, stock, qty) を作り、在庫不足なら throw new StockError(...) とすること。
在庫5の「ノート」に3個・5個の順に出荷を試み、「出荷しました:3個」「[StockError] 在庫が足りません(残り2個)」の2行を出力せよ。
コーディング★★★無料
期待される結果

出力2行が完全一致

ヒント

class StockError extends Error { constructor(m) { super(m); this.name = "StockError"; } } と書く。在庫は let で管理して減らしていく。

模範解答
class StockError extends Error {
  constructor(message) {
    super(message);
    this.name = "StockError";
  }
}

let stock = 5;

const ship = (qty) => {
  if (qty > stock) {
    throw new StockError(`在庫が足りません(残り${stock}個)`);
  }
  stock -= qty;
  return qty;
};

for (const qty of [3, 5]) {
  try {
    console.log(`出荷しました:${ship(qty)}個`);
  } catch (e) {
    console.log(`[${e.name}] ${e.message}`);
  }
}
解説

自作エラークラスを作ると、呼び出し側が「在庫の問題だけ」を選んで捕まえられるe instanceof StockError で判定でき、他のバグと混同しなくなる。

JS10-S05 【finally で後始末】data = ["10", "abc"] の各要素について、処理の開始と終了を必ず記録せよ。
「[10] 処理開始」→ 成功なら「→ 結果:100」(10倍)/失敗なら「→ 変換に失敗しました」→「[10] 処理終了」の順に出力し、最後に「完了:2件処理」と出力すること。
コーディング★★★無料
期待される結果

出力7行が完全一致

ヒント

ループの中で開始を出力 → try/catch → finally で終了を出力。finally はエラーの有無に関係なく実行される。

模範解答
const data = ["10", "abc"];

for (const d of data) {
  console.log(`[${d}] 処理開始`);

  try {
    const n = Number(d);
    if (Number.isNaN(n)) {
      throw new Error("変換失敗");
    }
    console.log(`→ 結果:${n * 10}`);
  } catch (e) {
    console.log("→ 変換に失敗しました");
  } finally {
    console.log(`[${d}] 処理終了`);
  }
}

console.log(`完了:${data.length}件処理`);
解説

finally があるので失敗した回でも必ず「処理終了」が記録される。実務ではここでファイルを閉じたり、ローディング表示を消したりする。書き忘れると画面がぐるぐる回り続ける原因になる。

5仕上げ課題

JS10-FINAL 【フォーム入力の検証システム】送信されたデータを1件ずつ検証し、不正な行はエラー内容を表示して飛ばし、正常な行だけを集計せよ。

const rows = [
 { name: "田中", age: "30", email: "tanaka@example.com" },
 { name: "鈴木", age: "abc", email: "suzuki@example.com" },
 { name: "", age: "25", email: "sato@example.com" },
 { name: "高橋", age: "45", email: "takahashi" },
 { name: "伊藤", age: "38", email: "ito@example.com" },
];


検証ルール(ValidationError という自作エラークラスで throw すること):
① 名前が空 → 「名前が未入力です」
② 年齢が数値に変換できない → 「年齢が不正です」
③ メールに @ が含まれない → 「メール形式が不正です」

出力仕様(9行):
=== 入力検証 ===
[1] OK 田中(30歳)
[2] NG 年齢が不正です
[3] NG 名前が未入力です
[4] NG メール形式が不正です
[5] OK 伊藤(38歳)
---
有効:2件 / エラー:3件
平均年齢:34.0歳
期待される結果

出力9行が完全一致

ヒント

class ValidationError extends Error を定義する。entries() で番号を振りながら回し、try の中で3つの検証を順に行う。メールの @ 判定は email.includes("@")。有効な行は配列に貯めて、最後に reduce で平均を出す(toFixed(1))。

模範解答
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

const rows = [
  { name: "田中", age: "30", email: "tanaka@example.com" },
  { name: "鈴木", age: "abc", email: "suzuki@example.com" },
  { name: "", age: "25", email: "sato@example.com" },
  { name: "高橋", age: "45", email: "takahashi" },
  { name: "伊藤", age: "38", email: "ito@example.com" },
];

console.log("=== 入力検証 ===");

const valid = [];
let errors = 0;

for (const [i, row] of rows.entries()) {
  try {
    if (!row.name) {
      throw new ValidationError("名前が未入力です");
    }

    const age = Number(row.age);
    if (Number.isNaN(age)) {
      throw new ValidationError("年齢が不正です");
    }

    if (!row.email.includes("@")) {
      throw new ValidationError("メール形式が不正です");
    }

    valid.push({ name: row.name, age });
    console.log(`[${i + 1}] OK ${row.name}(${age}歳)`);
  } catch (e) {
    console.log(`[${i + 1}] NG ${e.message}`);
    errors++;
  }
}

const averageAge = valid.reduce((sum, v) => sum + v.age, 0) / valid.length;

console.log("---");
console.log(`有効:${valid.length}件 / エラー:${errors}件`);
console.log(`平均年齢:${averageAge.toFixed(1)}歳`);
解説

検証は throw、対応は catch、失敗しても次の行へ——これが実務のデータ取り込み処理の完成形。5,000行のCSVに1行だけ壊れた行が混ざっていても、残り4,999行を処理し切れる。

この章で最も重要なのは、JavaScriptは放っておいてもエラーを出してくれないという事実だ。Number("abc") は NaN、10/0 は Infinity、Number("") は 0——どれも止まらずに進み、集計結果だけが静かに狂う。「エラーを捕まえる」以上に「自分でエラーを作り出す」ことが重要で、それが throw の役割になる。

次章からはブラウザの世界に入る。DOM操作を学ぶと、ここまで console.log に出していた結果を、実際の画面に表示できるようになる。