JavaScriptで開発をしていると、ブラウザのコンソールに「Uncaught ReferenceError: X is not defined」というエラーが表示されることがあります。このエラーはJavaScriptの中でも最も遭遇頻度の高いエラーの一つであり、初心者から経験者まで幅広い開発者が直面します。
このエラーの原因は多岐にわたり、変数の宣言忘れ、スコープの問題、スクリプトの読み込み順序、モジュールのimport忘れ、外部ライブラリの読み込み失敗など、さまざまなケースが考えられます。
この記事では、「is not defined」エラーのすべての原因パターンを網羅的に解説し、それぞれの具体的な解決方法をコード付きで紹介します。エラーメッセージの読み方から、実務でよくあるパターン、デバッグテクニックまで、この記事だけで完全に理解できる内容になっています。
この記事で学べること
- 「ReferenceError: X is not defined」エラーメッセージの正しい読み方
- 変数の宣言忘れ・タイポ・スコープ問題の特定と修正方法
- scriptタグの読み込み順序・defer/asyncによるエラーの原因と対策
- jQuery「$ is not defined」をはじめとするライブラリ関連エラーの解決
- ES Modules(import/export)関連のエラーパターンと修正
- Node.js環境での「document/window is not defined」への対処
- 非同期処理でのスコープ問題と解決策
- デバッグテクニックとエラーを未然に防ぐベストプラクティス
- 実務で頻出する10のパターンと即座に使える解決コード
「is not defined」エラーとは? ― ReferenceErrorの基本
まずは、このエラーの正体を正確に理解しましょう。「is not defined」エラーは、JavaScriptのReferenceErrorというエラー型に分類されるエラーです。
エラーメッセージの読み方
ブラウザのコンソールに表示される典型的なエラーメッセージを見てみましょう。
Uncaught ReferenceError: myVariable is not defined
at script.js:5:1
このエラーメッセージは以下の情報を含んでいます。
| 構成要素 |
内容 |
意味 |
| Uncaught |
Uncaught |
try-catchで捕捉されていないエラー |
| エラー型 |
ReferenceError |
存在しない参照(変数)へのアクセスエラー |
| 変数名 |
myVariable |
見つからなかった変数・関数・オブジェクトの名前 |
| エラー内容 |
is not defined |
その名前が現在のスコープで定義されていない |
| 発生場所 |
at script.js:5:1 |
ファイル名:行番号:列番号 |
ReferenceError が発生する仕組み
JavaScriptエンジンは、コードを実行する際にスコープチェーンを辿って変数を探します。変数が見つからない場合、ReferenceErrorがスローされます。
ReferenceError の発生例
// 変数 message は宣言されていない
console.log(message);
// Uncaught ReferenceError: message is not defined
この仕組みを図で表すと以下のようになります。
変数解決の流れ
- コード内で変数名(例:
message)が参照される
- JavaScriptエンジンが現在のスコープで変数を探す
- 見つからなければ外側のスコープを順番に探す(スコープチェーン)
- グローバルスコープまで探しても見つからない場合、
ReferenceErrorを投げる
ReferenceError と他のエラーの違い
「is not defined」(ReferenceError)は、他のよくあるエラーとは異なります。混同しやすいエラーとの違いを整理しましょう。
| エラー |
メッセージ例 |
意味 |
| ReferenceError |
X is not defined |
変数自体が存在しない |
| TypeError |
X is not a function |
変数は存在するが、関数として呼べない |
| TypeError |
Cannot read properties of undefined |
変数はundefinedで、そのプロパティにアクセスした |
| SyntaxError |
Unexpected token |
コードの文法自体が間違っている |
注意:「X is not defined」と「X is undefined」は全く別のエラーです。前者は変数自体が存在しないことを意味し(ReferenceError)、後者は変数は存在するが値がundefinedであることを意味します。
「is not defined」vs「is undefined」の違い
// ReferenceError: x is not defined(変数が存在しない)
console.log(x);
// undefined(変数は存在するが値が未設定)
let y;
console.log(y); // undefined(エラーにはならない)
コンソールでのエラー確認方法
ReferenceErrorが発生した場合、ブラウザの開発者ツール(DevTools)で詳細を確認できます。
開発者ツールの開き方
- Windows / Linux:
F12 キー、または Ctrl + Shift + I
- Mac:
Cmd + Option + I
- 右クリック → 「検証」(Inspect)
- Consoleタブを開くとエラーメッセージが赤字で表示されている
- エラーメッセージの右側にあるファイル名:行番号をクリックすると、エラー箇所のソースコードにジャンプできる
変数の宣言忘れ・タイポ
「is not defined」エラーの最も基本的な原因は、変数の宣言忘れやスペルミスです。シンプルですが、実際の開発でも頻繁に発生します。
変数を宣言せずに使った場合
let、const、varのいずれかで宣言せずに変数を参照すると、ReferenceErrorが発生します。
Uncaught ReferenceError: userName is not defined
エラーが出るコード
// 変数を宣言せずに使用
userName = "田中太郎";
console.log(userName);
// strict mode の場合: ReferenceError: userName is not defined
修正後のコード
// const または let で宣言する
const userName = "田中太郎";
console.log(userName); // "田中太郎"
注意:strict mode("use strict")を使用していない場合、宣言なしの代入はグローバル変数として作成されてしまいます。これはバグの原因になるため、常にstrict modeを使うか、let/constで宣言しましょう。ESモジュールは自動的にstrict modeになります。
変数名のスペルミス(大文字・小文字の違い)
JavaScriptは大文字・小文字を区別する(case-sensitive)言語です。変数名のスペルミスは非常に多い原因です。
Uncaught ReferenceError: Username is not defined
エラーが出るコード(大文字・小文字の違い)
const username = "田中太郎";
// 大文字・小文字を間違えている
console.log(Username); // ReferenceError: Username is not defined
console.log(userName); // ReferenceError: userName is not defined
console.log(USERNAME); // ReferenceError: USERNAME is not defined
修正後のコード
const username = "田中太郎";
// 宣言時と同じ名前を使う
console.log(username); // "田中太郎"
以下は、スペルミスのよくあるパターンです。
| 間違い |
正しい名前 |
ミスの種類 |
| document.getElementByID |
document.getElementById |
大文字・小文字 |
| addEventListner |
addEventListener |
スペル(e抜け) |
| querySelectorall |
querySelectorAll |
大文字・小文字 |
| innerHtml |
innerHTML |
大文字・小文字 |
| lenght |
length |
スペル(th/ht入替) |
| calback |
callback |
スペル(l抜け) |
const / let / var の宣言忘れ
関数の引数として受け取った値を使うつもりが、引数名を定義し忘れるケースもあります。
Uncaught ReferenceError: result is not defined
エラーが出るコード
function calculateTotal(price, tax) {
// result を宣言し忘れている
result = price + (price * tax);
return result;
}
// strict mode では ReferenceError
calculateTotal(1000, 0.1);
修正後のコード
function calculateTotal(price, tax) {
const result = price + (price * tax);
return result;
}
calculateTotal(1000, 0.1); // 1100
変数名と予約語の衝突
JavaScriptの予約語を変数名として使おうとすると、SyntaxErrorまたはReferenceErrorが発生することがあります。
予約語の使用例
// 以下は予約語のためエラーになる
const class = "初級"; // SyntaxError
const return = 42; // SyntaxError
const function = "test"; // SyntaxError
// 修正: 予約語を避けた変数名を使う
const className = "初級";
const returnValue = 42;
const funcName = "test";
ポイント:VSCodeなどのエディタを使用していれば、予約語を変数名にしようとすると即座にハイライトされます。エディタの警告機能を活用しましょう。
スコープの問題 ― 変数が見えない原因
変数は正しく宣言されているのに「is not defined」が発生する場合、スコープ(変数の有効範囲)の問題が原因であることが多いです。JavaScriptには複数のスコープがあり、それぞれの特性を理解することが重要です。
関数スコープ ― 関数の中で宣言した変数は外から見えない
関数内で宣言した変数は、その関数の中でのみ有効です。関数の外から参照しようとするとReferenceErrorが発生します。
Uncaught ReferenceError: localVar is not defined
エラーが出るコード
function greet() {
const localVar = "こんにちは";
console.log(localVar); // OK
}
greet();
console.log(localVar); // ReferenceError: localVar is not defined
修正方法1: 関数の外で宣言する
let localVar;
function greet() {
localVar = "こんにちは";
}
greet();
console.log(localVar); // "こんにちは"
修正方法2: 戻り値で返す(推奨)
function greet() {
const message = "こんにちは";
return message;
}
const result = greet();
console.log(result); // "こんにちは"
ブロックスコープ ― if文やfor文の中の変数
letとconstはブロックスコープを持ちます。{ }(波括弧)の中で宣言された変数は、そのブロックの外からはアクセスできません。
Uncaught ReferenceError: message is not defined
if文でのブロックスコープ問題
const score = 85;
if (score >= 80) {
const message = "合格です!";
}
console.log(message); // ReferenceError: message is not defined
修正後のコード
const score = 85;
let message;
if (score >= 80) {
message = "合格です!";
} else {
message = "不合格です";
}
console.log(message); // "合格です!"
for文でのブロックスコープ問題
for (let i = 0; i < 5; i++) {
const doubled = i * 2;
}
console.log(i); // ReferenceError: i is not defined
console.log(doubled); // ReferenceError: doubled is not defined
修正後のコード
const results = [];
for (let i = 0; i < 5; i++) {
results.push(i * 2);
}
console.log(results); // [0, 2, 4, 6, 8]
TDZ(Temporal Dead Zone)― let/const の巻き上げ問題
letとconstはホイスティング(巻き上げ)されますが、宣言行に到達するまではTDZ(Temporal Dead Zone)と呼ばれる状態になり、アクセスするとReferenceErrorが発生します。
Uncaught ReferenceError: Cannot access ‘greeting’ before initialization
TDZによるエラー
console.log(greeting); // ReferenceError: Cannot access 'greeting' before initialization
const greeting = "Hello";
var / let / const のホイスティングの違い
var: ホイスティングされ、undefinedで初期化される → エラーにならないが意図しない動作の原因に
let: ホイスティングされるが、TDZがあるため宣言前のアクセスはReferenceError
const: letと同様にTDZがある。加えて、必ず初期化が必要
var vs let のホイスティング比較
// var の場合: undefinedになる(エラーにはならない)
console.log(a); // undefined
var a = 10;
// let の場合: ReferenceError
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
クロージャでのスコープ問題
クロージャを使用する場合、変数のスコープに注意が必要です。
クロージャのスコープ問題
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(count); // ReferenceError: count is not defined
上記の例では、countはcreateCounter関数のスコープ内に閉じ込められているため、外部からは直接アクセスできません。これはクロージャのカプセル化の特性であり、意図的な設計です。
モジュールスコープ
ES Modulesを使用している場合、各モジュールは独自のスコープを持ちます。モジュール内で宣言された変数は、他のモジュールからは見えません。
moduleA.js
const SECRET_KEY = "abc123";
const API_URL = "https://api.example.com";
moduleB.js(エラーが出る)
// moduleA.js の変数は見えない
console.log(SECRET_KEY); // ReferenceError: SECRET_KEY is not defined
修正: export/importを使う
// moduleA.js(export追加)
export const SECRET_KEY = "abc123";
export const API_URL = "https://api.example.com";
// moduleB.js(import追加)
import { SECRET_KEY, API_URL } from './moduleA.js';
console.log(SECRET_KEY); // "abc123"
スクリプトの読み込み順序 ― HTMLでの配置ミス
Web開発において「is not defined」エラーが発生する非常に多い原因の一つが、スクリプトの読み込み順序の問題です。HTMLは上から順番に解析・実行されるため、依存関係のあるスクリプトの順序を正しく設定する必要があります。
scriptタグの読み込み順序が間違っている
あるスクリプトが別のスクリプトで定義された変数や関数を使用する場合、使用される側を先に読み込む必要があります。
Uncaught ReferenceError: utils is not defined
エラーが出るHTML(順序が逆)
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<!-- app.js が先に読み込まれてしまう -->
<script src="app.js"></script>
<script src="utils.js"></script>
</body>
</html>
修正後のHTML(正しい順序)
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
</head>
<body>
<!-- 依存されるスクリプトを先に読み込む -->
<script src="utils.js"></script>
<script src="app.js"></script>
</body>
</html>
DOMContentLoaded の前にDOM操作を行っている
HTMLの<head>内にスクリプトを配置すると、DOMの構築が完了する前にスクリプトが実行されます。この場合、DOM要素を参照しようとすると問題が発生します。
Uncaught TypeError: Cannot read properties of null (reading ‘textContent’)
エラーが出るHTML(headでDOM操作)
<html>
<head>
<script>
// DOM構築前に実行される
const title = document.getElementById("title");
title.textContent = "Hello"; // title は null → TypeError
</script>
</head>
<body>
<h1 id="title">タイトル</h1>
</body>
</html>
修正方法1: DOMContentLoadedイベントを使う
<head>
<script>
document.addEventListener("DOMContentLoaded", function() {
const title = document.getElementById("title");
title.textContent = "Hello"; // 正常に動作
});
</script>
</head>
修正方法2: bodyの末尾に配置する
<body>
<h1 id="title">タイトル</h1>
<!-- DOM要素の後にスクリプトを配置 -->
<script src="app.js"></script>
</body>
修正方法3: defer属性を使う(推奨)
<head>
<!-- defer: DOMの解析完了後に実行される -->
<script src="app.js" defer></script>
</head>
defer / async 属性の違いと影響
scriptタグにはdeferとasyncという属性があり、スクリプトの読み込みと実行タイミングを制御できます。これらの違いを理解することで、読み込み順序によるエラーを防げます。
| 属性 |
読み込み |
実行タイミング |
実行順序 |
| なし |
HTMLの解析を止めて読み込み |
読み込み完了後すぐ |
記述順 |
| defer |
並行して読み込み |
DOM解析完了後 |
記述順を保証 |
| async |
並行して読み込み |
読み込み完了後すぐ |
保証なし(早い者勝ち) |
注意:async属性を使うと、スクリプトの実行順序が保証されません。依存関係のあるスクリプトにはdeferを使用するか、asyncは使わないようにしましょう。
async で順序が狂う例
<!-- async は読み込み完了順に実行されるため、順序が保証されない -->
<script src="large-library.js" async></script>
<script src="app.js" async></script>
<!-- app.js が先に読み込み完了すると、library の関数が未定義でエラーに -->
外部スクリプトのロード失敗
外部ファイルのパスが間違っている場合や、ファイルが存在しない場合、スクリプトの読み込みに失敗します。この場合、そのスクリプトで定義されるはずだった変数や関数が存在せず、「is not defined」エラーが発生します。
GET http://localhost/js/utlis.js 404 (Not Found)
Uncaught ReferenceError: formatDate is not defined
よくあるパスの間違い
<!-- パスのスペルミス -->
<script src="js/utlis.js"></script> <!-- utils.js のスペルミス -->
<!-- 相対パスの間違い -->
<script src="utils.js"></script> <!-- 実際は js/ ディレクトリ内 -->
<!-- 修正 -->
<script src="js/utils.js"></script>
ポイント:ブラウザの開発者ツールの「Network」タブを確認すると、スクリプトファイルの読み込み状態(200 OK / 404 Not Found)を確認できます。ファイルが404になっていないか必ずチェックしましょう。
CDNからのライブラリ読み込み失敗
CDN(Content Delivery Network)からライブラリを読み込んでいる場合、ネットワークの問題やCDNの障害でライブラリの読み込みに失敗することがあります。
CDN読み込みのフォールバック
<!-- CDNから読み込み -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js"></script>
<!-- CDN失敗時のフォールバック -->
<script>
if (typeof _ === "undefined") {
// CDN読み込み失敗時、ローカルファイルを読み込む
document.write('<script src="/js/vendor/lodash.min.js"><\/script>');
}
</script>
外部ライブラリ・フレームワーク関連のエラー
外部ライブラリやフレームワークを使用する際に「is not defined」エラーが発生するケースは非常に多いです。特にjQueryの$に関するエラーは、Web開発で最も遭遇頻度の高い「is not defined」エラーの一つです。
jQuery: $ is not defined
jQueryを使用するコードで最も多いエラーが「$ is not defined」です。このエラーにはいくつかの原因があります。
Uncaught ReferenceError: $ is not defined
原因1: jQueryが読み込まれていない
エラーが出るコード(jQuery未読み込み)
<!-- jQueryのscriptタグがない! -->
<script>
$("#myButton").click(function() {
alert("クリックされました");
});
</script>
修正: jQueryを先に読み込む
<!-- jQueryを先に読み込む -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script>
$("#myButton").click(function() {
alert("クリックされました");
});
</script>
原因2: jQueryの読み込み順序が間違っている
エラーが出るコード(順序が逆)
<!-- 自分のスクリプトが先 -->
<script src="app.js"></script>
<!-- jQueryが後 -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
原因3: WordPressでjQueryを使う場合
WordPressではjQueryがnoConflictモードで読み込まれるため、$ではなくjQueryを使う必要があります。
WordPress での jQuery の正しい使い方
// 方法1: jQuery を使う
jQuery("#myButton").click(function() {
alert("クリック");
});
// 方法2: 即時実行関数で $ を使えるようにする(推奨)
(function($) {
$("#myButton").click(function() {
alert("クリック");
});
})(jQuery);
// 方法3: jQuery(document).ready のコールバックで $ を受け取る
jQuery(document).ready(function($) {
$("#myButton").click(function() {
alert("クリック");
});
});
React / Vue / Angular が読み込まれていない
フレームワークを使用する際にも、読み込みの問題で「is not defined」エラーが発生することがあります。
Uncaught ReferenceError: React is not defined
React: CDNで使う場合
<!-- React本体を先に読み込む -->
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<!-- その後にアプリケーションコード -->
<script src="app.js"></script>
React: npm プロジェクトでの import 忘れ
// React 17以前: import が必須
import React from 'react';
// React 17以降: 新しいJSXトランスフォームを使えばimport不要
// ただし、babel/tsconfig の設定が必要
ポイント:React 17以降では、新しいJSXトランスフォーム(react-jsx)を使用すれば、import React from 'react'を省略できます。ただし、React.createElementなどを直接使う場合は引き続きimportが必要です。
Vue.js が読み込まれていない
Uncaught ReferenceError: Vue is not defined
Vue.js のCDN読み込み修正
<!-- Vue.js を先に読み込む -->
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<div id="app">{{ message }}</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return { message: "Hello Vue!" };
}
}).mount("#app");
</script>
lodash / moment 等のユーティリティライブラリ
lodashやmomentなどのユーティリティライブラリも、読み込み方法によってエラーが発生します。
Uncaught ReferenceError: _ is not defined
| ライブラリ |
グローバル変数名 |
CDN読み込み |
| jQuery |
$ / jQuery |
code.jquery.com |
| Lodash |
_ |
cdn.jsdelivr.net/npm/lodash |
| Moment.js |
moment |
cdn.jsdelivr.net/npm/moment |
| Axios |
axios |
cdn.jsdelivr.net/npm/axios |
| Three.js |
THREE |
cdn.jsdelivr.net/npm/three |
CDN読み込み vs npm install の違い
CDN読み込み(グローバル変数として使える)
<!-- CDN読み込み → グローバルに _ が定義される -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4/lodash.min.js"></script>
<script>
_.chunk([1, 2, 3, 4], 2); // [[1, 2], [3, 4]]
</script>
npm install(import が必要)
// npm install lodash 後
import _ from 'lodash';
_.chunk([1, 2, 3, 4], 2); // [[1, 2], [3, 4]]
// または必要な関数だけimport(バンドルサイズ削減)
import { chunk } from 'lodash';
chunk([1, 2, 3, 4], 2);
モジュール(import/export)の問題
ES Modules(ESM)を使った開発では、import/exportに関連する「is not defined」エラーが頻繁に発生します。モジュールシステムの仕組みを理解することで、これらのエラーを効率的に解決できます。
import 忘れ
モジュールからエクスポートされた関数や変数を使う場合、必ずimport文で読み込む必要があります。
Uncaught ReferenceError: formatDate is not defined
utils.js(エクスポート側)
export function formatDate(date) {
return date.toLocaleDateString("ja-JP");
}
app.js(エラーが出る – import忘れ)
// import文が書かれていない
const today = formatDate(new Date());
// ReferenceError: formatDate is not defined
app.js(修正後)
import { formatDate } from './utils.js';
const today = formatDate(new Date());
console.log(today); // "2026/3/8"
named export vs default export の間違い
exportにはnamed exportとdefault exportの2種類があり、import側の書き方が異なります。間違えると「is not defined」エラーの原因になります。
| 種類 |
export側 |
import側 |
| named export |
export function foo() {} |
import { foo } from ‘…’ |
| default export |
export default function() {} |
import foo from ‘…’ |
| 両方 |
export default + export |
import foo, { bar } from ‘…’ |
よくある間違い: named export を {} なしで import
// utils.js - named export
export function formatDate(date) { ... }
// app.js - 間違い({} がない)
import formatDate from './utils.js';
// formatDate は undefined になる(default exportがないため)
// app.js - 正しい
import { formatDate } from './utils.js';
type=”module” の指定忘れ
ブラウザでES Modulesのimport/exportを使用するには、scriptタグにtype="module"を指定する必要があります。
Uncaught SyntaxError: Cannot use import statement outside a module
エラーが出るHTML
<!-- type="module" がない -->
<script src="app.js"></script>
修正後のHTML
<!-- type="module" を追加 -->
<script type="module" src="app.js"></script>
注意:type="module"を使うと、スクリプトは自動的にstrict modeになり、deferと同様にDOM解析後に実行されます。また、CORSの制約があるため、ローカルファイルをfile://で開くと動作しません。ローカルサーバーを使用してください。
CommonJS(require)との混在
Node.jsのCommonJSモジュール(require)とES Modules(import)を混在させると、エラーが発生します。
ReferenceError: require is not defined in ES module scope
ESMファイルでrequireを使った場合
// package.json で "type": "module" が設定されている場合
// .js ファイルは ESM として扱われる
const fs = require("fs"); // ReferenceError: require is not defined
修正方法
// 方法1: import を使う
import fs from 'fs';
import { readFile } from 'fs/promises';
// 方法2: createRequire で require を作る
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const pkg = require('./package.json');
// 方法3: ファイル拡張子を .cjs にする(CommonJSとして扱われる)
| モジュール方式 |
読み込み構文 |
拡張子 |
環境 |
| ES Modules |
import / export |
.mjs / .js |
ブラウザ / Node.js |
| CommonJS |
require / module.exports |
.cjs / .js |
Node.js のみ |
DOM要素関連の「is not defined」
ブラウザ固有のオブジェクト(document、window、navigatorなど)は、Node.js環境やSSR(サーバーサイドレンダリング)環境では存在しません。これらを参照すると「is not defined」エラーが発生します。
document is not defined(Node.js環境)
Node.jsはサーバーサイドの実行環境であり、DOMの概念がありません。ブラウザ用のコードをNode.jsで実行しようとすると、このエラーが発生します。
ReferenceError: document is not defined
Node.js で document を使用(エラー)
// server.js(Node.js)
const title = document.getElementById("title");
// ReferenceError: document is not defined
解決方法1: 環境を判定する
// ブラウザ環境かどうかを判定
if (typeof document !== "undefined") {
// ブラウザ環境でのみ実行
const title = document.getElementById("title");
}
解決方法2: jsdom を使う(テスト目的)
// npm install jsdom
import { JSDOM } from 'jsdom';
const dom = new JSDOM('<html><body><h1 id="title">Hello</h1></body></html>');
const document = dom.window.document;
const title = document.getElementById("title");
console.log(title.textContent); // "Hello"
window is not defined(SSR / Node.js環境)
Next.jsやNuxt.jsなどのSSRフレームワークでは、サーバーサイドでコードが実行される際にwindowオブジェクトが存在しません。
ReferenceError: window is not defined
Next.js での window エラーと修正
// エラーが出るコード
const width = window.innerWidth; // SSR時にエラー
// 修正方法1: typeof チェック
const width = typeof window !== "undefined" ? window.innerWidth : 0;
// 修正方法2: useEffect 内で実行(Reactの場合)
import { useState, useEffect } from 'react';
function MyComponent() {
const [width, setWidth] = useState(0);
useEffect(() => {
// useEffect はクライアント側でのみ実行される
setWidth(window.innerWidth);
}, []);
return <div>幅: {width}px</div>;
}
navigator is not defined
navigatorもブラウザ固有のオブジェクトです。ユーザーエージェントの取得やGeolocation APIなどを使う場合、環境チェックが必要です。
navigator の安全なアクセス
// 安全にnavigatorにアクセスする
function getUserAgent() {
if (typeof navigator !== "undefined") {
return navigator.userAgent;
}
return "";
}
// モバイル判定の安全な実装
function isMobile() {
if (typeof navigator === "undefined") return false;
return /Android|iPhone|iPad/i.test(navigator.userAgent);
}
alert / confirm / prompt is not defined(Node.js)
alert、confirm、promptはブラウザのwindowオブジェクトのメソッドであり、Node.jsには存在しません。
ReferenceError: alert is not defined
Node.jsでの代替手段
// ブラウザの alert の代わりに console.log を使用
console.log("メッセージ");
// ユーザー入力が必要な場合は readline モジュールを使用
import readline from 'readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question("名前を入力してください: ", (answer) => {
console.log(`こんにちは、${answer}さん!`);
rl.close();
});
ブラウザ固有オブジェクトまとめ
以下のオブジェクトはブラウザ環境でのみ利用可能です。Node.jsやSSR環境で使用する場合は、必ずtypeofチェックを行いましょう。
window / self / globalThis(ブラウザではwindowを指す)
document / DOM API全般
navigator / location / history
localStorage / sessionStorage
alert / confirm / prompt
fetch(Node.js 18以降では利用可能)
非同期処理での「is not defined」
非同期処理はJavaScriptの根幹をなす機能ですが、スコープやタイミングの問題で「is not defined」エラーが発生することがあります。
非同期処理の結果を同期的に使おうとした場合
非同期関数の戻り値をそのまま使おうとすると、値がまだ返されていないタイミングでアクセスしてしまうことがあります。
エラーが出るコード(非同期の結果を同期的に使用)
let userData;
fetch("/api/user")
.then(response => response.json())
.then(data => {
userData = data;
});
// fetchが完了する前に実行される
console.log(userData.name); // TypeError: Cannot read properties of undefined
修正方法1: then チェーン内で処理する
fetch("/api/user")
.then(response => response.json())
.then(data => {
// データの処理は then の中で行う
console.log(data.name);
updateUI(data);
})
.catch(error => {
console.error("取得失敗:", error);
});
修正方法2: async/await を使う(推奨)
async function loadUser() {
try {
const response = await fetch("/api/user");
const userData = await response.json();
console.log(userData.name); // 正常にアクセス可能
updateUI(userData);
} catch (error) {
console.error("取得失敗:", error);
}
}
loadUser();
コールバック内のスコープ
コールバック関数内で外部の変数を参照する場合、タイミングによっては期待と異なる値になることがあります。
コールバックのスコープ問題(var の場合)
// var はブロックスコープを持たない
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 3, 3, 3(全て3になる)
}, 1000);
}
修正: let を使う
// let はブロックスコープを持つ
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // 0, 1, 2(期待通り)
}, 1000);
}
Promise / async-await での変数スコープ
async/awaitを使う場合でも、awaitの結果を関数の外に持ち出そうとすると問題が発生します。
async 関数の結果を外で使おうとする(問題)
async function fetchData() {
const response = await fetch("/api/data");
return response.json();
}
// 注意: async関数は常にPromiseを返す
const data = fetchData();
console.log(data); // Promise { <pending> }(データではない!)
修正: await で結果を待つ
// トップレベルawait(ES2022、モジュール環境で利用可能)
const data = await fetchData();
console.log(data); // 実際のデータ
// または別のasync関数内で使用
async function main() {
const data = await fetchData();
console.log(data);
}
main();
setTimeout 内の変数参照
setTimeoutのコールバックは遅延実行されるため、変数の値がコールバック実行時点のものになります。
setTimeout で変数が変わってしまう例
let message = "Hello";
setTimeout(() => {
console.log(message); // "Goodbye"(変更後の値)
}, 1000);
message = "Goodbye"; // setTimeout実行前に変更される
修正: 値をクロージャで閉じ込める
let message = "Hello";
// 即時実行関数で現在の値を閉じ込める
(function(currentMessage) {
setTimeout(() => {
console.log(currentMessage); // "Hello"
}, 1000);
})(message);
message = "Goodbye";
Node.js 固有の問題
Node.jsはブラウザとは異なる実行環境であり、固有の「is not defined」エラーが発生します。ブラウザ向けのコードをNode.jsで実行したり、その逆のケースで問題が起きます。
ブラウザ固有API(window, document)の使用
先のセクションでも触れましたが、Node.jsにはブラウザのグローバルオブジェクトが存在しません。環境によって使用できるグローバル変数が異なります。
| オブジェクト |
ブラウザ |
Node.js |
| window |
あり |
なし(globalThisで代替) |
| document |
あり |
なし |
| navigator |
あり |
なし |
| process |
なし |
あり |
| __dirname |
なし |
CJS: あり / ESM: なし |
| require |
なし |
CJS: あり / ESM: なし |
| globalThis |
あり(= window) |
あり(= global) |
global vs globalThis
globalThisは、ブラウザとNode.jsの両方で使えるグローバルオブジェクトへの参照です。環境に依存しないコードを書く際に便利です。
環境に依存しないグローバルオブジェクトアクセス
// どの環境でも動作する
const global = globalThis;
// グローバル変数の設定
globalThis.myConfig = {
apiUrl: "https://api.example.com",
debug: true
};
// ブラウザ: window.myConfig
// Node.js: global.myConfig
// 両方: globalThis.myConfig
__dirname / __filename(ESM環境での問題)
Node.jsのCommonJS環境では__dirnameと__filenameが自動的に提供されますが、ESM(ES Modules)環境では使用できません。
ReferenceError: __dirname is not defined in ES module scope
ESMで__dirnameの代替を作る
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
console.log(__dirname); // 現在のディレクトリパス
console.log(__filename); // 現在のファイルパス
process が undefined(ブラウザ環境)
processはNode.js固有のグローバルオブジェクトです。ブラウザ環境には存在しないため、環境変数にアクセスしようとするとエラーになります。
Uncaught ReferenceError: process is not defined
ブラウザでprocess.envを使おうとした場合
// ブラウザではprocess は存在しない
const apiKey = process.env.API_KEY;
// ReferenceError: process is not defined
解決方法(ビルドツール使用時)
// Vite の場合: import.meta.env を使用
const apiKey = import.meta.env.VITE_API_KEY;
// webpack の場合: DefinePlugin で定義
// webpack.config.js
const webpack = require("webpack");
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.API_KEY': JSON.stringify(process.env.API_KEY)
})
]
};
// Create React App の場合: REACT_APP_ プレフィックス
const apiKey = process.env.REACT_APP_API_KEY;
// CRAのwebpack設定が自動的に置換してくれる
ポイント:環境変数をブラウザで使いたい場合は、ビルドツール(Vite, webpack, CRAなど)の仕組みを利用して、ビルド時に値を埋め込むのが一般的です。直接process.envをブラウザで参照することはできません。
デバッグと予防テクニック
「is not defined」エラーを効率的にデバッグし、そもそもエラーを発生させないための予防テクニックを紹介します。
typeof で安全にチェックする
変数が定義されているかどうかを安全に確認するには、typeof演算子を使います。typeofは未定義の変数に対してもReferenceErrorを発生させない唯一の方法です。
typeof による安全なチェック
// 直接参照するとエラー
if (myVar) { ... } // ReferenceError: myVar is not defined
// typeof を使えばエラーにならない
if (typeof myVar !== "undefined") {
// myVar が定義されている場合のみ実行
console.log(myVar);
}
// 実用例: jQueryの存在チェック
if (typeof jQuery !== "undefined") {
jQuery("#app").show();
} else {
console.warn("jQueryが読み込まれていません");
}
// 実用例: 環境判定
const isNode = typeof process !== "undefined" && process.versions != null;
const isBrowser = typeof window !== "undefined";
try-catch でエラーをハンドリング
ReferenceErrorが発生する可能性がある箇所をtry-catchで囲むことで、アプリケーション全体のクラッシュを防げます。
try-catch でのエラーハンドリング
try {
// ライブラリが読み込まれているか不明な場合
const chart = new Chart(ctx, config);
} catch (error) {
if (error instanceof ReferenceError) {
console.error("Chart.jsが読み込まれていません。CDNを確認してください。");
} else {
throw error; // 他のエラーは再スロー
}
}
window.onerror / window.addEventListener でグローバルキャッチ
捕捉されなかったエラーをグローバルでキャッチして、ログに記録したりユーザーに通知したりできます。
グローバルエラーハンドリング
// 方法1: window.onerror
window.onerror = function(message, source, lineno, colno, error) {
console.error("エラー:", message);
console.error("ファイル:", source, "行:", lineno);
// エラーをサーバーに送信するなど
return true; // trueでコンソールへのエラー表示を抑制
};
// 方法2: addEventListener(より詳細な情報)
window.addEventListener("error", function(event) {
if (event.error instanceof ReferenceError) {
console.warn("未定義の変数へのアクセス:", event.error.message);
}
});
// 方法3: Promiseの未処理エラーもキャッチ
window.addEventListener("unhandledrejection", function(event) {
console.error("未処理のPromise拒否:", event.reason);
});
ESLint の no-undef ルール
ESLintのno-undefルールを使うと、コードを実行する前に未定義の変数参照を検出できます。
.eslintrc.json の設定
{
"rules": {
"no-undef": "error",
"no-use-before-define": "error"
},
"env": {
"browser": true,
"node": true,
"es2022": true
},
"globals": {
"jQuery": "readonly",
"$": "readonly"
}
}
ESLintの便利なルール
no-undef: 未定義の変数の使用を禁止
no-use-before-define: 宣言前の変数使用を禁止
no-unused-vars: 未使用の変数を検出
no-redeclare: 同じ変数の再宣言を禁止
no-shadow: 外部スコープの変数と同名の変数宣言を禁止
ブラウザ開発者ツールの活用
ブラウザの開発者ツールは「is not defined」エラーのデバッグに欠かせません。以下の手順で効率的にデバッグできます。
デバッグ手順
- Consoleタブ: エラーメッセージと発生場所(ファイル名:行番号)を確認
- Sourceタブ: エラー行にブレークポイントを設定して、変数の状態を確認
- Networkタブ: スクリプトファイルの読み込みが成功しているか(404になっていないか)確認
- Consoleでテスト:
typeof 変数名を実行して変数の存在を確認
- Scope確認: ブレークポイントで停止中にScopeパネルで利用可能な変数を確認
コンソールでのデバッグテクニック
// 変数の存在確認
typeof myVariable; // "undefined" なら未定義
// グローバル変数の一覧を見る
Object.keys(window).filter(key => !key.startsWith("webkit"));
// スクリプトが読み込まれているか確認
document.querySelectorAll("script").forEach(s => console.log(s.src));
// ブレークポイント: debugger文を使用
debugger; // ここで実行が停止し、DevToolsで変数を確認できる
実務でよくあるパターン10選
ここでは、実際の開発現場で最も頻繁に遭遇する「is not defined」エラーのパターンとその解決方法を紹介します。
パターン1: jQuery「$ is not defined」
最も多いパターンです。jQueryの読み込み前にjQueryコードが実行されています。
Uncaught ReferenceError: $ is not defined
解決コード
<!-- 1. jQueryを先に読み込む -->
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<!-- 2. その後に自分のスクリプト -->
<script src="app.js"></script>
パターン2: Google Analytics「gtag is not defined」
Google Analyticsのトラッキングコードの読み込み前にgtag関数を呼び出した場合に発生します。
Uncaught ReferenceError: gtag is not defined
解決: 正しいGA4の設置方法
<!-- Google tag (gtag.js) をhead内の上部に配置 -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
</script>
<!-- カスタムイベントを送る場合は安全にチェック -->
<script>
if (typeof gtag === "function") {
gtag('event', 'click', { event_category: 'button' });
}
</script>
パターン3: React「React is not defined」(JSX Transform)
React 17より前のプロジェクトで、JSXを使用するファイルにimport Reactがない場合に発生します。
ReferenceError: React is not defined
解決方法
// 方法1: React をインポートする(React 17より前)
import React from 'react';
// 方法2: 新しいJSXトランスフォームを有効にする(React 17以降)
// tsconfig.json または babel設定で:
// "jsx": "react-jsx"
パターン4: 「process is not defined」(ブラウザ環境)
Node.js用のコードをブラウザで実行した場合、またはwebpackの設定が不足している場合に発生します。
Uncaught ReferenceError: process is not defined
解決方法
// 安全にprocess.envにアクセスする
const isProduction = typeof process !== "undefined"
&& process.env
&& process.env.NODE_ENV === "production";
パターン5: 「module is not defined」(ブラウザ環境)
CommonJSモジュール形式で書かれたコードをブラウザで直接読み込んだ場合に発生します。
Uncaught ReferenceError: module is not defined
問題のコード(CommonJS形式)
// Node.js/CommonJS形式 → ブラウザでは使えない
module.exports = { myFunction };
解決: ES Modules を使う
// ES Modules形式に書き換え
export { myFunction };
// またはwebpack/Vite等のバンドラーでビルドする
パターン6: 「require is not defined」(ESM環境)
ReferenceError: require is not defined in ES module scope, you can use import instead
解決: importに書き換え
// 変更前(CommonJS)
const express = require("express");
// 変更後(ESM)
import express from 'express';
パターン7: 「localStorage is not defined」(SSR環境)
ReferenceError: localStorage is not defined
解決: 安全にアクセスする
// 安全なlocalStorageラッパー
function getFromStorage(key) {
if (typeof localStorage !== "undefined") {
return localStorage.getItem(key);
}
return null;
}
function saveToStorage(key, value) {
if (typeof localStorage !== "undefined") {
localStorage.setItem(key, value);
}
}
パターン8: 「fetch is not defined」(古いNode.js環境)
ReferenceError: fetch is not defined
解決方法
// 方法1: Node.js 18以降にアップグレード(fetch がビルトイン)
// node --version で確認
// 方法2: node-fetch パッケージを使用
// npm install node-fetch
import fetch from 'node-fetch';
const response = await fetch("https://api.example.com/data");
const data = await response.json();
パターン9: 「regeneratorRuntime is not defined」
async/awaitを使用したコードをBabelでトランスパイルする際に、ポリフィルが不足している場合に発生します。
Uncaught ReferenceError: regeneratorRuntime is not defined
解決方法
// 方法1: @babel/plugin-transform-runtime を使用
// npm install -D @babel/plugin-transform-runtime
// npm install @babel/runtime
// babel.config.json:
{
"plugins": ["@babel/plugin-transform-runtime"]
}
// 方法2: core-js をインポート
import 'core-js/stable';
import 'regenerator-runtime/runtime';
パターン10: 「Buffer is not defined」(ブラウザ環境)
BufferはNode.jsのグローバルオブジェクトであり、ブラウザには存在しません。
Uncaught ReferenceError: Buffer is not defined
解決方法
// ブラウザではTextEncoderやUint8Arrayを使用
const encoder = new TextEncoder();
const data = encoder.encode("Hello World");
const decoder = new TextDecoder();
const text = decoder.decode(data);
// Base64 エンコード/デコード(ブラウザ)
const base64 = btoa("Hello World");
const original = atob(base64);
まとめ ― 解決フローチャートとベストプラクティス
この記事では、JavaScriptの「ReferenceError: X is not defined」エラーについて、あらゆる原因パターンと解決方法を解説しました。最後に、エラーに遭遇した際の解決フローチャートとベストプラクティスをまとめます。
エラー解決フローチャート
「is not defined」エラーが発生したら、以下の順番で原因を特定しましょう。
「is not defined」エラー解決フロー
- エラーメッセージを確認: どの変数/関数が「not defined」なのか特定する
- スペルチェック: 変数名にタイポ(大文字/小文字含む)がないか確認する
- 宣言の確認: その変数は
let/const/var で宣言されているか?
- スコープの確認: 別のスコープ(関数内/ブロック内/モジュール内)で宣言されていないか?
- 読み込み順序の確認: スクリプトの読み込み順序は正しいか?
- Networkタブ確認: スクリプトファイルの読み込みが404になっていないか?
- import/require確認: モジュールの場合、import文を書き忘れていないか?
- 環境の確認: ブラウザ固有API(window/document)をNode.jsで使っていないか、その逆はないか?
- TDZの確認:
let/constを宣言前に使っていないか?
- 非同期処理の確認: 非同期処理の完了前に変数にアクセスしていないか?
関連エラーとの違い
「is not defined」と混同しやすいエラーを再度整理します。
| エラーメッセージ |
意味 |
対処法 |
| X is not defined |
変数X自体が存在しない |
変数の宣言・import・スクリプト読み込み確認 |
| X is not a function |
Xは存在するが関数ではない |
型の確認、正しいメソッド名の使用 |
| Cannot read properties of undefined |
undefinedのプロパティにアクセス |
オプショナルチェーン(?.)の使用 |
| Cannot read properties of null |
nullのプロパティにアクセス |
DOM要素の取得結果のnullチェック |
| Cannot access before initialization |
TDZ内でのアクセス |
変数宣言の順序を修正 |
ベストプラクティス
「is not defined」エラーを未然に防ぐために、以下のベストプラクティスを実践しましょう。
ベストプラクティス10選
- 常に
const / let で変数を宣言する(varは使わない)
- ESLintの
no-undef ルールを有効にする(実行前にエラーを検出)
- scriptタグには
defer 属性を使用する(読み込み順序の保証)
- ES Modulesを使用する(
import/exportでモジュール管理)
- strict mode を有効にする(暗黙のグローバル変数を防止)
- 環境固有のAPIにアクセスする前に
typeof チェックする
- 外部ライブラリの読み込み失敗に備えてフォールバックを用意する
- TypeScriptを導入する(コンパイル時に未定義変数を検出)
- VS Codeの IntelliSense を活用する(変数名の自動補完でタイポ防止)
- コードレビューで変数のスコープを意識する
予防コードのまとめ
"use strict"; // strict mode を有効に
// 1. 常に const/let で宣言
const API_URL = "https://api.example.com";
let count = 0;
// 2. typeof で安全にチェック
if (typeof window !== "undefined") {
// ブラウザ固有の処理
}
// 3. try-catch で保護
try {
initLibrary();
} catch (e) {
console.warn("ライブラリの初期化に失敗:", e.message);
}
// 4. オプショナルチェーンを活用
const value = obj?.property?.nested;
// 5. Nullish Coalescing でデフォルト値
const name = userData?.name ?? "ゲスト";
「ReferenceError: X is not defined」は、JavaScriptでの開発で最も基本的でありながら、原因が多岐にわたるエラーです。この記事で紹介したパターンと解決方法を参考に、エラーに遭遇した際は冷静に原因を特定してください。また、ESLintやTypeScriptなどのツールを導入することで、多くの「is not defined」エラーをコードを書く段階で防ぐことができます。