1.エラーメッセージは手がかりです
コードを書き始めたばかりのころは、赤いエラーがよく出ます。プロの開発者も同じです。違いは、エラーを見て慌てるか、手がかりとして読むかにあります。エラーを見つけて直す作業をデバッグといいますが、その第一歩はメッセージを最後まで、一文字ずつ読むことです。メッセージにはたいてい、直すべき場所の名前がそのまま書かれています。
JavaScriptのエラーメッセージはエラー名: 説明という形です。たとえばTypeError: Cannot read properties of undefined (reading 'length')は、「種類はTypeError(値の種類が合わない)、内容はundefinedからlengthを読もうとした」という意味です。この練習場は、実行中に起きたエラーなら何行目で起きたかも一緒に表示します。その行が出発点です。
知っておきたい点が二つあります。一つ目に、説明の文言はブラウザによって少しずつ違います。この講義のメッセージはクローム系のブラウザが使うV8エンジンの文言で、ほかのブラウザでは同じエラーが別の言い回しで出ることがあります。エラー名(TypeErrorなど)は言語の決まりで定められているので、ほとんどどのブラウザでも同じです。二つ目に、エラーが起きた行とミスをした行は違うことがあります。値がおかしく作られた場所は上のほうにあり、その値を使ったところで壊れたのが下のほう、ということがよくあります。
エラーが起きると、実行はその行で止まります。そのため、エラーより前のconsole.logは出力され、後ろのものは出力されません。この性質は「どこまで正しく動いたか」を教えてくれる手がかりになります。下のコードは、最初の行が出力されたあと3行目で止まります。
words[2]は存在しない要素なのでundefinedconst words = ["りんご", "なし"];
console.log(words[0].length);
console.log(words[2].length);
console.log("ここは実行されない");3
TypeError: Cannot read properties of undefined (reading 'length')- エラー名 — どんな種類の問題か(
SyntaxError、ReferenceError、TypeError、RangeError…) - 説明 — 何をしようとして行き詰まったか(どの名前、どのプロパティ)
- 行番号 — どこで止まったか(ミスをした場所はそれより上かもしれない)
2.`SyntaxError` — そもそも実行されないエラー
SyntaxErrorは文法エラーです。かっこを閉じていない、カンマが抜けている、同じ名前を二回宣言した、といったように、コードがJavaScriptの文として読めないときに起きます。ほかのエラーと違って、コードを実行する前の読み込みの段階で引っかかるので、一行も実行されません。先頭にconsole.logを入れても何も出力されないなら、まず文法エラーを疑ってください。
この練習場は、文法エラーのときは行番号なしでメッセージだけを表示します。そのぶん、メッセージの中の手がかりが大切になります。missing ) after argument listは関数呼び出しの閉じかっこがないという意味で、Unexpected identifier 'price'は「priceが出てくるはずのない場所に出てきた」、つまりそのすぐ前にカンマなどが抜けているという意味です。Unexpected tokenが見えたら、その文字のすぐ前を調べます。名前が引用符で示されていれば、その名前で検索して場所を探すと早く見つかります。
文法エラーはたいてい、対応が合わないところで起きます。開きかっこ・波かっこ・引用符それぞれに閉じる相方があるかを確かめ、インデントをそろえてみると、対応がずれたところが目につきます。エディターが対応するかっこを強調してくれる機能も大いに役立ちます。長いコードを一度に書かず、数行ずつ書いて実行してみれば、文法エラーが出たときに今書いた数行だけを見れば済みます。
console.log("こんにちは";SyntaxError: missing ) after argument listpriceのすぐ前、つまり上の行の末尾のカンマが抜けているconst item = {
name: "りんご"
price: 1500
};SyntaxError: Unexpected identifier 'price'let count = 0;
let count = 1;SyntaxError: Identifier 'count' has already been declaredJSON.parseで読むときに出るエラーも、名前はSyntaxErrorです。ただしこれはコードの文法ではなく「データの文法」が間違っているもので、実行中に起きるので行番号も表示されます。JSONが壊れているかどうかは、JSONフォーマッターに貼り付ければどこが間違っているかがすぐわかります。3.`ReferenceError` — そんな名前はありません
ReferenceErrorは「その名前が見つからない」というエラーです。いちばん多い原因はタイプミスです。consoleをConsoleと書いたり、totalをtotlaと書いたりすると、JavaScriptはその名前の変数がないと教えてくれます。大文字と小文字も別の名前として扱われます。メッセージのis not definedの前にある名前をそのままコピーしてコードの中を検索すれば、つづりが違うところがすぐ見つかります。
二つ目の原因は「宣言する前に使う」ことです。let・constで作った変数を宣言した行より上で使うと、Cannot access 'price' before initializationになります。三つ目はスコープ(有効範囲)です。第5講で見たように、関数や{ }ブロックの中で作った変数はその外からは見えません。繰り返しの中で作った変数を、繰り返しが終わったあとで使おうとするとis not definedになります。
この練習場のように厳格モードで動くコードでは、letやconstなしで初めて見る名前に値を入れることもReferenceErrorになります。厳格モードでなければ、このミスは黙って新しいグローバル変数を作ってしまい、もっと見つけにくいバグになりますが、厳格モードはそれをすぐエラーとして知らせてくれます。
const total = 100;
console.log(totla);ReferenceError: totla is not definedconsole.log(price);
const price = 1500;ReferenceError: Cannot access 'price' before initializationfor (let i = 0; i < 3; i++) {
const last = i;
}
console.log(last);ReferenceError: last is not defined4.`TypeError` — その値ではできないこと
TypeErrorは値の種類に合わないことをさせたというエラーで、初心者のうちにいちばんよく出会います。代表はCannot read properties of undefined (reading '…')です。undefinedやnullにはプロパティがないのに、ドット(.)をつけて何かを取り出そうとしたという意味です。かっこの中の名前が取り出そうとしたプロパティで、そのドットのすぐ左にある値がundefinedでした。
大事なのは「なぜその値がundefinedになったのか」です。JavaScriptは、存在しない配列の要素(arr[5])や存在しないプロパティ(user.nmae)を取り出すときにエラーを出さず、黙ってundefinedを返します。エラーが起きるのは、そのundefinedをもう一度使った瞬間です。だから、エラーの行のドットの左の値をconsole.logで出力してみて、その値がどこから来たのかを上へさかのぼる必要があります。犯人はたいてい、インデックスの範囲、プロパティ名のタイプミス、関数がreturnを書き忘れてundefinedを返した場合のどれかです。
もう一つよく見るのが… is not a functionです。関数ではないものをかっこ()で呼んだ場合で、メソッド名のタイプミス(toUppercase)か、別の種類の値にそのメソッドを呼んだかのどちらかです。たとえばtoFixedは数値のメソッドなので、文字列"1500"に対して呼ぶとこのエラーになります。第2講で見た型変換の問題とつながるところです。constで作った変数にもう一度値を入れたときのAssignment to constant variable.もTypeErrorです。
undefined — エラーはその次に起きるconst user = { name: "健太" };
console.log(user.nmae);
console.log(user.nmae.length);undefined
TypeError: Cannot read properties of undefined (reading 'length')const s = "hello";
console.log(s.toUppercase());TypeError: s.toUppercase is not a functiontoFixedがないconst price = "1500";
console.log(typeof price);
console.log(price.toFixed(0));string
TypeError: price.toFixed is not a function| エラー名 | 意味 | よくあるメッセージ | まず見るところ |
|---|---|---|---|
SyntaxError | 文として読めない | missing ) after argument list | かっこ・カンマ・引用符の対応 |
ReferenceError | そんな名前はない | x is not defined | つづり・大文字小文字・宣言の位置・スコープ |
TypeError | その値ではできないこと | Cannot read properties of undefined | ドットの左の値がどこから来たか |
RangeError | 値が許される範囲を外れた | Maximum call stack size exceeded | 負の数・大きすぎる数・終わらない再帰 |
5.`RangeError`、そしてエラーにならないバグ
RangeErrorは、値の種類は合っているのに範囲がおかしいというエラーです。"*".repeat(-1)のように負の回数を渡したり、new Array(-1)のように負の長さを渡したりすると起きます。関数が自分自身を果てしなく呼び続けるとMaximum call stack size exceededになり、クローム系(V8)ではこれもRangeErrorです(ファイアフォックスは同じ状況をInternalError: too much recursionで知らせます)。関数が自分自身を呼ぶ再帰には、必ず止まる条件が必要です。
もっと厄介なのは、エラーにならないバグです。コードは最後まで動いたのに、結果だけが間違っている場合です。第4講で見たoff-by-one(一つずれ)が代表例です。i <= arr.lengthで繰り返すと、最後に存在しない要素を取り出してundefinedを足すことになり、数値にundefinedを足すとエラーではなくNaNになります。0で割るとInfinity、0 / 0はNaNになるだけで、エラーは出ません。結果にNaN・undefined・Infinityが見えたら、エラーメッセージがなくてもバグのサインです。
終わらない繰り返しもエラーメッセージを出しません。whileの条件がずっと真なら、プログラムはひたすら回り続けます。この練習場は、実行が2秒以内に終わらなければ強制的に止めて、時間制限にかかったと知らせます。その案内が出たら、繰り返しの終了条件を疑ってください。条件に使う変数が繰り返しの中で実際に変わっているか、終わりに近づく方向に変わっているかを見ます。実際のブラウザのタブで無限ループを回すとタブが固まることがあるので、繰り返しを書いたばかりのときは回数の少ない入力から試します。
function stars(n) {
return "*".repeat(n);
}
console.log(stars(3));
console.log(stars(-1));***
RangeError: Invalid count value: -1NaN — off-by-oneconst nums = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= nums.length; i++) {
sum += nums[i];
}
console.log(sum);
console.log(10 / 0, 0 / 0);NaN Infinity NaN
6.デバッグの手順 — 出力し、仮説を立て、絞り込む
デバッグには決まった手順があります。まず「期待した結果」と「実際の結果」を一文ずつ書き出します。次に原因について仮説を一つ立て(例:繰り返しが一回多く回っている)、それを確かめられるいちばん小さな実験をします。仮説が正しければ直し、間違っていればそれを消して次の仮説に進みます。何か所も同時に変えると、どれが直したのかわからなくなるので、一度に一つだけ変えます。
いちばん手軽な実験道具はconsole.logです。怪しいところの値を出力してみれば、「頭の中の値」と「実際の値」がどこから食い違い始めるのかが見えます。繰り返しの中では番号と値を一緒に出力し、値の横にラベルをつければ(console.log("i:", i))、出力が混ざっても迷いません。typeofも一緒に出力すると、"1500"(文字列)と1500(数値)のように見た目が同じ値も区別できます。問題が見つかったら、確認用の出力は消します。
コードが長いときは最小再現を作ります。バグがそのまま現れる範囲で関係のない行を一行ずつ消していき、問題を起こすいちばん短いコードを残すことです。削っていく途中で原因が見えることも多く、人やAIに尋ねるときも、短いコードのほうがずっと的確な答えが返ってきます。説明しているうちに答えが見えてくることもあるので、コードを一行ずつ声に出して説明してみる方法(ラバーダック・デバッグ)も広く使われています。
NaNを出力します。どうやって原因を探せばよいでしょうか。const sales = [10, 20, 30];
let sum = 0;
for (let i = 0; i <= sales.length; i++) {
console.log("i:", i, "値:", sales[i]);
sum += sales[i];
}
console.log(sum / sales.length);i: 0 値: 10 i: 1 値: 20 i: 2 値: 30 i: 3 値: undefined NaN
- ステップ1 期待と実際を書き出します。期待:20、実際:
NaN。エラーメッセージはないので、結果だけが間違うバグです。 - ステップ2 仮説:「足している値の中に数値でないものが混じっている」。繰り返しの中で
iとsales[i]を出力してみます。 - ステップ3 出力を見ると、
i: 3のとき値がundefinedです。配列は0〜2番しかないのに、3番まで回っています。 - ステップ4 条件
i <= sales.lengthをi < sales.lengthに直し、空の配列や要素一つの配列でも試します。
undefinedを足していました。<に直せば20になります。7.AIにエラーを尋ねるときに渡すもの
AIコーディングアシスタントは、エラーメッセージを説明し、直す方向を示すのにかなり役立ちます。ただし、受け取った情報の分しか正確になれません。「動きません、直してください」よりも、エラーメッセージの全文、問題が起きる最小のコード、期待した結果と実際の結果、実行環境(ブラウザ・エンジン)、すでに試したことを一緒に渡すほうが、ずっと的確な答えが返ってきます。エラーメッセージは要約せず、そのままコピーして貼り付けてください。翻訳したり縮めたりすると、大事な手がかり(名前・プロパティ・行番号)が消えてしまいます。
貼り付ける前に必ず取り除くべきものもあります。パスワード、APIキー、アクセストークン、実在の顧客の名前・電話番号のような個人情報は、コードやデータに紛れていても消して、偽の値に置き換えます。会社や学校のコードなら、外部のAIに貼り付けてよいかどうか、まずそこの規則を確かめます。この点は第10講でさらに詳しく扱います。
AIが直したコードを受け取ったら、そのまま信じずに確かめます。元のエラーが消えたか、期待した結果が出るか、空の配列や0のような境界値でも正しいかを、自分で実行してみます。AIはもっともらしいけれど間違った説明をすることがあり、エラーを隠すだけのやり方(例:問題の値を無条件に0に変える)で「直す」こともあります。なぜそう直したのか説明を求め、その説明がエラーメッセージと合っているかを吟味してください。
- エラーメッセージの全文(名前・説明・行番号)— そのままコピー
- 問題が現れるいちばん短いコード(最小再現)
- 期待した結果と実際の結果
- 実行環境(どのブラウザか、この練習場か など)と、すでに試したこと
- パスワード・キー・実在の個人情報は抜いて偽の値に
📌 要点まとめ
- エラーメッセージは「名前: 説明」と行番号で読む — 説明の文言はブラウザによって少し違うが、名前は同じ
SyntaxErrorは実行前に引っかかって一行も動かず、ReferenceErrorは名前の問題、TypeErrorは値の種類の問題、RangeErrorは範囲の問題undefinedは黙って生まれ、あとで壊れる — エラーの行のドットの左の値がどこから来たかをさかのぼるNaN・Infinity・終わらない繰り返しは、エラーメッセージなしでやって来るバグのサイン — 練習場は2秒たつと実行を止める- 期待・実際を書く → 仮説を一つ →
console.logで確かめる → 最小再現、そしてAIにはメッセージ全文と短いコードを秘密情報抜きで渡す
🧪 コード実習
どの最初のコードにも、バグが一つずつ隠れています。まずそのまま実行してエラーメッセージや間違った結果を読み、原因を見つけて一か所だけ直し、テストを通してください。
コードはこのブラウザの中の隔離された場所でだけ実行され、サーバーには送られません。ネットワークには接続できず、2秒を超えると止まります。書き換えたコードはこのブラウザにだけ保存されます。Ctrl+Enter(⌘+Enter)で実行、Tabキーは空白2つ(Escの後のTabで次へ移動)。
JavaScriptが無効なので実行はできませんが、問題・最初のコード・自動チェックの内容・解答例はそのまま読めます。
1名前のタイプミスを直す
価格priceと割引率rate(例:0.1は10%)を受け取り、割引後の価格を返す関数discount(price, rate)です。実行するとReferenceErrorが出ます。メッセージに出てきた名前を見て直してください。
discount(10000, 0.1)期待値9000discount(5000, 0.5)期待値2500discount(3000, 0)期待値3000discount(0, 0.2)期待値0
💡 ヒント
prise is not defined — その名前がどこにあるかを探して、引数の名前と比べてみてください。
解答例を見る
function discount(price, rate) {
const off = price * rate;
return price - off;
}2存在しないメソッドを直す
文字列sをすべて大文字にし、末尾に"!"をつけて返す関数shout(s)です。実行するとTypeError: s.toUppercase is not a functionが出ます。原因を見つけて直してください。空文字列なら"!"を返します。
shout("hi")期待値"HI!"shout("Hello World")期待値"HELLO WORLD!"shout("あいう")期待値"あいう!"shout("")期待値"!"
💡 ヒント
JavaScriptの名前は大文字と小文字を区別します。第7講で使ったメソッド名のつづりを一文字ずつ比べてみてください。
解答例を見る
function shout(s) {
return s.toUpperCase() + "!";
}3NaNになる平均を直す
数値の配列numsの平均を返す関数average(nums)です。空の配列なら0を返します。エラーは出ないのに結果がNaNになります。繰り返しの中でiとnums[i]を出力してみて、原因を探してください。
average([10,20,30])期待値20average([7])期待値7average([1,2])期待値1.5average([-5,5])期待値0average([])期待値0
💡 ヒント
console.log("i:", i, nums[i]);を繰り返しの中に入れてみてください。最後に出力される値は何ですか。
解答例を見る
function average(nums) {
if (nums.length === 0) return 0;
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
}
return sum / nums.length;
}4終わらない繰り返しを直す
正の整数nを受け取り、nから1まで逆に数えた配列を返す関数countDown(n)です。例:countDown(3) → [3, 2, 1]、countDown(0) → []。最初のコードは終わらないので、練習場が2秒後に実行を止めます。繰り返しの終了条件を調べて直してください。
countDown(3)期待値[3,2,1]countDown(1)期待値[1]countDown(5)期待値[5,4,3,2,1]countDown(0)期待値[]
💡 ヒント
条件n > 0がいつか偽になるには、繰り返しの中でnがどう変わる必要があるでしょうか。
解答例を見る
function countDown(n) {
const out = [];
while (n > 0) {
out.push(n);
n--;
}
return out;
}🤖 AIにはこう聞いてみましょう
コピーして [ ] の部分を自分の状況に書き換えて使います。答えはそのまま信じず、本文と比べて確かめましょう。
エラーメッセージの意味がわからないとき
JavaScriptを[ブラウザ/練習場]で実行したら、次のエラーが出ました:[エラーメッセージの全文をそのまま]。問題が起きるコードはこれです:[最小のコード]。このエラーが何を意味するのかやさしい言葉で説明し、私のコードのどの行のどの値が原因である可能性が高いかを順番に教えてください。すぐに答えを出す前に、私が`console.log`で確かめるべき場所を先に教えてください。
エラーはないのに結果が間違っているとき
次の関数はエラーなしで動きますが、結果が間違っています。入力:[入力]、期待した結果:[期待]、実際の結果:[実際]。コード:[最小のコード]。原因の仮説を2〜3個立てて、それぞれの仮説を確かめる`console.log`の位置を教えてください。直したコードを出すときは、何をなぜ変えたのかと、境界値(空の配列、0)のテストも一緒に出してください。
AIが直してくれたコードを検証するとき
あなたが直してくれたコードが元の問題を本当に解決したか確かめたいです。元のエラー:[メッセージ]、直したコード:[コード]。変えた行ごとに理由を説明し、エラーを隠すだけの修正(例:値を無条件に0にする)になっていないか自分で点検してください。このコードが失敗しうる入力も3つ挙げてください。
🧰 関連ツール
この講義で扱ったJSON・正規表現・テキストを、その場で確かめたり整えたりできるツールです。本物の個人情報やパスワードは貼り付けないでください。
- MDN Web Docs — JavaScriptエラーリファレンス(JavaScript error reference)
- MDN Web Docs — SyntaxError、ReferenceError、TypeError、RangeError
- MDN Web Docs — 厳格モード(Strict mode)
- Chrome DevToolsドキュメント — JavaScriptのデバッグを始める
学習目標をすべて達成できたら完了を押しましょう。
このブラウザでは保存できないため、この画面でのみ表示されます。