Get to know MDN better
このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。
このレッスンでは、JavaScript のデバッグ(何が間違っている?で最初に見た内容)に戻ります。ここでは、エラーを特定するためのテクニックをさらに深く掘り下げていきますが、同時に、問題に直面する前に避けるために、防御的にコードを作成し、コード内のエラーを処理する方法も説明します。
| HTMLおよびCSS の基礎を理解し、これまでのレッスンで説明した JavaScript を把握していること。 |
|
このモジュールの前半では、「何が間違っている?」で、 JavaScript プログラムで発生しうるエラーの種類を広く見ていき、それらは大まかに構文エラーと論理エラーの 2 種類に分類できると述べました。また、 JavaScript のエラーメッセージの一般的な種類を理解するのに役立つ情報も提供し、 console.log() 文を使用して単純なデバッグを行う方法を示しました。
この記事では、エラーを特定するためのツールについて詳しく見ていくほか、そもそもエラーを防ぐ方法についても検討していきます。
特定のエラーの原因を突き止める前に、まずコードの検証を行うべきです。W3C の Markup validation service、CSS validation service、JavaScript リンター(ESLint など)を使用して、コードが有効であることを確認しましょう。これにより、いくつかのエラーが見つかると思われますが、それらを修正することで、残りのエラーに集中できるようになります。
コードをウェブページにコピー&ペーストして、その有効性を何度も確認するのはあまり便利ではありません。コードエディターにリンタープラグインをインストールし、コードを書いている最中にエラーを報告してもらうことをお勧めします。コードエディターのプラグインまたは拡張機能のリストで ESLint を検索し、インストールしてみてください。
JavaScriptには、注意すべき一般的な問題がいくつかあります。例えば、次のようなものがあります。
例えば、 bad-for-loop.html (ソースコードを参照)では、 var で定義した変数を使って 10 回の反復処理をループし、そのたびに段落を作成して onclick イベントハンドラーを追加しています。クリックされると、それぞれにその番号(作成した時点での i の値)を格納したアラートメッセージが表示されるようにします。なぜなら、 for ループはネストされた関数を呼び出す前にすべての反復処理を行うからです。
最も簡単な解決策は、反復処理変数を var の代わりに let で宣言することです。動作するバージョンについては good-for-loop.html (ソースコードも参照)を参照してください。
メモ: Buggy JavaScript Code: The 10 Most Common Mistakes JavaScript Developers Make には、これらのよくある間違いについての解説などがあります。
ブラウザーの開発者ツールには、 JavaScript のデバッグを行うために便利な機能がたくさんあります。手始めに、 JavaScript コンソールはコードのエラーを報告してくれます。
fetch-broken のサンプルをローカルにコピーしてください(ソースコードも参照してください)。
コンソールを見ると、エラーメッセージが表示されます。正確な文言はブラウザーによりますが、 "Uncaught TypeError: heroes is not iterable" のようなものです。参照されている行番号は 25 です。ソースコードを見ると、関連するコードセクションは次のとおりです。
すなわち、 jsonObj (期待通り、 JSON オブジェクトであるはずです)を使用しようとすると、すぐにコードが崩れてしまいます。これは、外部の .json ファイルから、以下の fetch() 呼び出しを使用して取得することになっています。
ただし、これは失敗します。
このコードのどこが間違っているかは、すでにお分かりかもしれませんが、その原因をどのように突き止めるかを見てみましょう。手始めに、コンソール API を使って、 JavaScript コードがブラウザーにある JavaScript コンソールと対話することができます。利用できる機能はたくさんありますが、一番多く使用するのは console.log() で、コンソールに独自のメッセージを出力します。
次のように、 console.log() 呼び出しを追加し、 fetch() の返値をログ出力してみてください。
ブラウザーのページを更新してください。今度は、エラーメッセージの前に、コンソールに記録された新しいメッセージが表示されます。
レスポンスの値: [object Promise]console.log() の出力は、 fetch() の返値が JSON データではなく Promise であることを示しています。 fetch() 関数は非同期です。ネットワークから実際のレスポンスを受け取ったときにのみ履行される Promise を返します。レスポンスを使用することができますが、その前に Promise が履行されるのを待つ必要があります。
少し脱線しますが、別のコンソールメソッドを使ってエラーを報告してみましょう — console.error()。コード内の
を、次のものに置き換えてください。
コードを保存してブラウザーを更新してください。すると、メッセージがエラーとして報告され、その下にある未処理のエラーと同じ色とアイコンが表示されます。さらに、メッセージの横に展開/折りたたみ用の矢印が表示されます。これをクリックすると、エラーが発生した JavaScript ファイル内の行を示す 1 行が表示されます。実際、未処理のエラーの行にも同様のものがありますが、2 行表示されています。
showHeroes http://localhost:7800/js-debug-test/index.js:25 <anonymous> http://localhost:7800/js-debug-test/index.js:10これは、先ほど指摘したように、エラーの原因が showHeroes() 関数の 25 行目にあることを意味します。コードを確認すると、10 行目の無名関数が showHeroes() を呼び出していることがわかります。これらの行はコールスタックと呼ばれ、コード内の複数の箇所にまたがるエラーの原因を特定する際に大いに役立ちます。
このケースでは console.error() の呼び出しは特に有用ではありませんが、コールスタックがまだ用意されていない場合に、それを生成するのに役立つことがあります。
さて、エラーの修正に戻りましょう。fetch() 呼び出しの最後に then() メソッドをチェーンすることで、解決された Promise からのレスポンスにアクセスできます。その後、得られたレスポンス値を、次のように、それを受け取る関数に渡すことができます。
保存してページを更新し、コードが動作するか確認してください。ネタバレ注意 — 上記の変更では問題は解決していません。残念ながら、まだ同じエラーが発生しています!
メモ: まとめると、何かうまく動作しないときや、コードのある点で値が意味している値になっていないように見えるときはいつでも、console.log()、console.error()、その他の値を表示する関数を使用してそれを出力し、何が起こっているのかを確認することができます。
ブラウザー開発者ツールのより洗練された機能、 Firefox でいうところの JavaScript デバッガーを使って、この問題を調査してみましょう。
メモ: 他のブラウザーでも似たツールが利用できます。 Chrome のソースタブ、 Safari の Debugger (Safari Web Development Toolsを参照)などです。
Firefoxでは、デバッガータブは次のようになります。
このようなツールの主な特徴は、コードにブレークポイントを追加できることです。ブレークポイントとは、コードの実行が停止する位置のことで、その位置で現在の状態の環境を調べ、何が起こっているかを確認することができます。
ブレークポイントを試してみましょう。
私たちはここでとても有益な情報を得ることができます。
showHeroes() の引数は fetch() のプロミスが履行された値です。つまり、このプロミスには JSON 形式のデータが含まれていません。これは Response オブジェクトです。レスポンスの内容を JSON オブジェクトとして取得するには、追加の手順が必要となります。
自分自身でこの問題を解決してみてください。まずは Response オブジェクトのドキュメントを参照してください。もし行き詰まったら、 https://github.com/mdn/learning-area/tree/main/tools-testing/cross-browser-testing/javascript/fetch-fixed に修正されたソースコードがあります。
メモ: デバッガータブには、ここでは説明していない他にも多くの便利な機能があります。例えば、条件付きブレークポイントやウォッチ式などです。より多くの情報については、デバッガーページを参照してください。
HTML と CSS は寛容な言語です。エラーや認識されない機能があっても、その言語の性質上、処理できることがよくあります。例えば、 CSS は認識されないプロパティを無視し、残りのコードは動作することがよくあります。しかし、JavaScript は HTML や CSS ほど寛容ではありません。JavaScript エンジンが誤りや認識できない構文を検出すると、多くの場合、エラーが発生します。
コード内の JavaScript エラーを処理するための一般的な手法について見ていきましょう。以下の節では、まず下に示すテンプレートファイルをローカルマシンに "handling-errors.html" としてコピーし、開始タグ <script> と終了タグ </script> の間にコードスニペットを追加します。その後、そのファイルをブラウザーで開き、開発者ツールの JavaScript コンソールで出力を確認するように進めていきます。
JavaScript の条件分岐の一般的な用途は、エラーの処理です。条件分岐を使用すると、変数の値に応じて異なるコードを実行することができます。多くの場合、値が存在しない場合や型が間違っている場合にエラーが発生するのを防ぐため、あるいは値が原因で誤った結果が返され、後々問題を引き起こす可能性がある場合にエラーを捕捉するために、この機能を活用することが推奨されます。
例を見てみましょう。ユーザーの身長をインチ単位で引数として受け取り、小数点以下 2 桁でメートル単位の身長を返す関数があるとします。その関数は次のような形になるでしょう。
例のファイルの <script> 要素内で、height という名前の const を宣言し、値として 70 を割り当ててください。
上記の関数を、前の行の下にコピーしてください。
関数を呼び出し、引数として height 定数を渡し、返値をコンソールへ出力してください。
ブラウザーでサンプルを読み込み、開発者ツールの JavaScript コンソールを確認してください。そこに 1.78 という値が記録されているはずです。
これ単体では問題なく動作します。しかし、提供されたデータが欠落していたり、間違っていたりした場合はどうなるでしょうか?以下のシナリオを試してみてください。
言うまでもなく、これらの結果はどれも良いものではありません。では、不適切なデータからどう身を守ればよいのでしょうか?
計算を行う前に、データが正しいかどうかを確認するための条件分岐を関数内に追加してみましょう。現在の関数を以下のコードに置き換えてみてください。
さて、最初の 2 つのシナリオをもう一度試してみると、問題を解決するために何が必要かがお分かりいただけるよう、少し分かりやすいメッセージが返されるはずです。ここには、num の値を修正するためのコードを実行するなど、好きなものを何でも記述できますが、これはお勧めできません。この関数には単純な目的が一つあるだけであり、値の修正はシステムの別の場所で処理すべきだからです。
メモ: if() 文では、まず typeof 演算子を使用して num のデータ型が "number" であるかどうかを判定し、次にNumber.isNaN(num) が false を返すかどうかを判定します。これは、num が NaN に設定されているという特定のケースに対処するために必要な処理です。なぜなら、typeof NaNは依然として「number」を返すからです!
しかし、3 つ目のシナリオをもう一度試してみると、やはり "Uncaught ReferenceError: height is not defined" というエラーが発生してしまいます。その値を使用しようとしている関数の内部から、その値が利用できないという事実を修正することはできません。
これにはどう対処すればよいでしょうか?正しいデータを受け取れなかった場合、関数がカスタムエラーを返すようにした方が良いでしょう。まずはその方法を見てから、すべてのエラーを一括して処理する方法を検討しましょう。
コード内の任意の場所で、throw 文と Error() コンストラクターを組み合わせて、カスタムエラーを発生させることもできます。実際にどのように動作するか見てみましょう。
関数内の else ブロックにある console.log() の行を、次の行に置き換えてください。
例をもう一度実行してみてください。ただし、num が不正な値(つまり、数値ではない値)に設定されていることを確認してください。今回は、カスタムエラーが発生し、エラーの原因を特定するのに役立つコールスタックが表示されるはずです(ただし、メッセージには依然としてエラーが「未捕捉」または「未処理」であると表示される点にご注意ください)。さて、エラーは厄介なものですが、関数が正常に実行されたものの、後で問題を引き起こす可能性のある数値以外の値を返すよりも、はるかに有用な方法です。
では、これらのエラーにはどう対処すればよいのでしょうか?
try...catch 文は、エラー処理に特化したものです。これは次のような構造です。
try ブロック内では、あるコードの実行を試みます。このコードがエラーを発生させることなく実行されれば、問題はなく、catch ブロックは無視されます。しかし、エラーが発生した場合は、catch ブロックが実行されます。これにより、エラーを表す Error オブジェクトにアクセスできるようになり、エラーを処理するためのコードを実行することができます。
コード内で try...catch を使用しましょう。
スクリプトの最後にある inchesToMeters() 関数を呼び出す console.log() の行を、以下のブロックに置き換えてください。これで、console.log() の行を try ブロック内で実行し、そこで発生したエラーを対応する catch ブロック内で処理するようになりました。
保存して更新すると、次の 2 つの項目が表示されるはずです。
では、num を正しい数値に更新してみてください。そうすれば、エラーメッセージは表示されず、計算結果がログに記録されるのが確認できるはずです。
これは重要な点です。これで、発生したエラーはすべて処理されるため、アプリケーションがクラッシュすることはなくなります。エラーを処理するために、任意のコードを実行することができます。上記では基本的なメッセージをログに出していますが、例えば、ユーザーに身長を再入力するよう求める関数を呼び出し、今回は入力エラーを修正するよう促すこともできます。また、if...else 文を使用して、返されるエラーの種類に応じて異なるエラー処理コードを実行することも可能です。
機能検出は、すべてのブラウザーで対応していない可能性のある新しい JavaScript 機能を使用する場合に有用です。機能の有無を確認し、その結果に応じてコードを実行することで、その機能に対応しているブラウザーと対応していないブラウザーの両方で、適切なユーザー体験を提供することができます。簡単な例として、位置情報 API(ウェブブラウザーが動作している端末で利用可能な位置情報を公開する)には、それを利用するための主要エントリーポイント、つまりグローバルな Navigator オブジェクトで利用可能な geolocation プロパティを持っています。したがって、先ほど見たのと同様の if() 構文を使用することで、ブラウザーが位置情報機能に対応しているかどうかを判別することができます。
機能検出のその他の例については、UA スニッフィングの代替手段をご覧ください。
JavaScript(および HTML と CSS)では他にも多くの課題があります。オンラインで答えを探す方法についての知識は非常に貴重です。
対応している情報源として最適なのは、MDN、stackoverflow.com、caniuse.com などです。
補助的なものとして、問題の解決策を調べるために、お気に入りの検索エンジンで検索してみてください。 特定のエラーメッセージをお持ちの場合は、それを検索すると役立つことが多いでしょう。他にも、あなたと同じ問題を抱えている開発者は多いでしょう。
以上が JavaScript でのデバッグとエラー処理です。単純でしょう? それほど単純ではないかもしれませんが、この記事は少なくとも出発点となり、JavaScript に関連する問題に取り組むためのアイディアをいくつか与えてくれるはずです。
JavaScript モジュールを使った動的スクリプトについては以上です。お疲れ様でした。次のモジュールでは、JavaScript フレームワークやライブラリーについて役立つ情報を提供します。
This page was last modified on 2026年3月27日 by MDN contributors.
Your blueprint for a better internet.
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998–2026 by individual mozilla.org contributors. Content available under a Creative Commons license.