ReferenceError: x is not defined の原因と直し方
存在しない変数・関数名を参照したときに出るエラーです。タイプミスだけでなく、let/constのブロックスコープの外から参照した場合にも同じエラーになります。
エラーメッセージの読み方
main.js:2
main.js- ファイル名
2- 行番号 — 実際にクラッシュした行
ReferenceError- 例外クラス — 何が起きたか。ここを検索するのが最短です
totall is not defined- 内容 — 期待していたもの、または受け付けられなかったもの
このエラーが出る典型パターン
パターン1
1 let total = 100; 2 console.log(totall); ^
変数名のスペルミスです。JavaScriptは大文字小文字を区別するため、Totalとtotalも別の名前として扱われます。
直し方: totall を total にします。
パターン2
1 function square(n) { 2 return n * n; 3 } 4 console.log(squre (4)); ^
関数名のスペルミスです。定義したsquareと1文字でも違うと、別の名前として扱われ見つけられません。
直し方: squre を square にします。
パターン3
1 if (true) { 2 let total = 42; ^ 3 } 4 console.log(total);
letは波括弧で囲まれたブロックの中だけで通用します。ブロックの外から参照するとReferenceErrorになります。varで宣言すればブロックスコープを持たず、ファイル全体から参照できます。
直し方: let を var にします。
パターン4
1 const config = { debug: true }; 2 console.log(Config ); ^
先頭を大文字にした綴りは別の名前として扱われます。定義したconfigとは一致しません。
直し方: Config を config にします。
パターン5
1 { 2 const secret = 42; 3 } 4 console.log(secret); ^
波括弧だけのブロックでもスコープは区切られます。中で宣言したconstはブロックの外からは見えません。
直し方: secret を "ok" にします。
よくある誤解
varで宣言した変数はブロックの外からでも参照できますが、letやconstは波括弧の中でしか通用しません。以前書いたvarの感覚のままブロックの外に出ると、その瞬間にエラーになります。
実務での勘所
実はletやconstもvarと同じようにスコープの先頭で「予約」されています(巻き上げ)。ただしvarと違い、実際の宣言行に達するまでは「一時的死角(Temporal Dead Zone)」という状態に置かれ、その間にアクセスするとReferenceError: Cannot access 'x' before initializationという、このトピックの「そもそも存在しない」エラーとは文言も原因も異なる例外になります。x is not definedと出ている場合はそのスコープのどこにも宣言が無いことを意味し、Cannot access before initializationと出ている場合は宣言はあるが実行がそこにまだ到達していないことを意味するため、エラー文言の違いで原因の切り分けができます。