タイトル: エラー一覧
SEOタイトル: JavaScript よくあるエラー集と対処
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li><strong>JavaScript の頻出エラー</strong>と原因・対処をまとめて把握する</li><li>TypeError 系: <strong>Cannot read properties of undefined / null</strong> → 値の存在確認、Optional Chaining (<code>?.</code>)</li><li>ReferenceError: <strong>x is not defined</strong> → スペルミス / let/const のスコープ / 読み込み順</li><li>SyntaxError: <strong>Unexpected token</strong> → 括弧 / カンマ / JSON.parse 失敗</li><li>デバッグ: <strong>DevTools の Console / Sources / Network</strong> + Source Maps + try/catch</li></ul></td></tr></table>
<h2>JavaScript エラーの分類</h2>
<p>JavaScript のエラーは大きく<strong>シンタックスエラー (構文エラー)</strong> と<strong>実行時エラー</strong>に分かれます。実行時エラーは <code>Error</code> オブジェクトを継承した複数のサブクラスがあります。</p>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>クラス</th><th>意味</th><th>典型例</th></tr></thead>
<tbody>
<tr><td><strong>SyntaxError</strong></td><td>構文として不正</td><td>括弧の閉じ忘れ、JSON.parse 失敗</td></tr>
<tr><td><strong>TypeError</strong></td><td>値の型が予期しない</td><td>undefined のプロパティアクセス、関数でないものを呼ぶ</td></tr>
<tr><td><strong>ReferenceError</strong></td><td>定義されていない変数</td><td>スペルミス、TDZ、グローバル参照</td></tr>
<tr><td><strong>RangeError</strong></td><td>範囲外の値</td><td>再帰深すぎ、Array 長過剰</td></tr>
<tr><td><strong>URIError</strong></td><td>URI 関数の不正</td><td><code>decodeURI('%')</code></td></tr>
<tr><td><strong>EvalError</strong></td><td>eval の不正 (現在ほぼ未使用)</td><td>-</td></tr>
<tr><td>AggregateError</td><td>複数エラー集約</td><td>Promise.any 全 reject</td></tr>
</tbody>
</table>
<h2>頻出エラー 1: Cannot read properties of undefined</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught TypeError: Cannot read properties of undefined (reading 'name')
Uncaught TypeError: Cannot read property 'name' of undefined (旧表記)
Uncaught TypeError: Cannot read properties of null (reading 'value')</code></pre>
<p>最頻出エラー。undefined または null の値に対してプロパティ / メソッドアクセスしようとした場合に発生。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ よくある原因
const user = users.find(u => u.id === 999); // 見つからない → undefined
console.log(user.name); // ❌ TypeError
const el = document.getElementById('foo'); // 要素が無い → null
el.value = 'x'; // ❌ TypeError
// ✅ 対策 1: 存在チェック
if (user) {
console.log(user.name);
}
// ✅ 対策 2: Optional Chaining (ES2020+)
console.log(user?.name); // user が undefined/null なら undefined
console.log(user?.address?.city); // ネストも安全
// ✅ 対策 3: デフォルト値 (Nullish Coalescing)
const name = user?.name ?? '匿名';
// ✅ 対策 4: 配列メソッドは空配列で代用
const items = data?.items ?? [];
items.forEach(...); // 空でも安全</code></pre>
<h2>頻出エラー 2: x is not defined</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught ReferenceError: foo is not defined
Uncaught ReferenceError: $ is not defined ← jQuery が読まれていない
Uncaught ReferenceError: process is not defined ← ブラウザで Node 変数を使った</code></pre>
<p>存在しない変数を参照した場合に発生。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ スペルミス
const userName = 'taro';
console.log(usrName); // ❌ ReferenceError
// ❌ スクリプト読み込み順
// <script src="my-code.js"></script> ← jQuery より先に読まれている
// <script src="jquery.js"></script>
$('button').click(...); // ❌ $ is not defined
// ❌ let/const の TDZ (Temporal Dead Zone)
console.log(x); // ❌ Cannot access 'x' before initialization
let x = 10;
// ✅ 対策: スペルチェック、読み込み順、宣言を先に
// jQuery / ライブラリは先に読み込む
// または defer 属性、または DOMContentLoaded 後に実行</code></pre>
<h2>頻出エラー 3: Unexpected token</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught SyntaxError: Unexpected token '}'
Uncaught SyntaxError: Unexpected token in JSON at position 0
Uncaught SyntaxError: Unexpected end of JSON input</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ 括弧 / カンマ不一致
const obj = { a: 1, b: 2, }; // 末尾カンマ→OK (ES2017+)
const arr = [1, 2 3]; // ❌ Unexpected number
// ❌ JSON.parse 失敗
JSON.parse('hello world'); // ❌ Unexpected token h
JSON.parse(''); // ❌ Unexpected end
JSON.parse("{'name':'taro'}"); // ❌ Unexpected token ' (シングルクォート不可)
// ✅ try/catch でラップ
function safeParse(text, fallback = null) {
try {
return JSON.parse(text);
} catch (e) {
console.warn('JSON parse failed:', e.message);
return fallback;
}
}</code></pre>
<h2>頻出エラー 4: Maximum call stack size exceeded</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught RangeError: Maximum call stack size exceeded</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ 無限再帰
function factorial(n) {
return n * factorial(n - 1); // 終了条件なし
}
factorial(5); // ❌ スタックオーバーフロー
// ✅ 終了条件
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// ✅ 深い再帰はループに変換
function factorialIter(n) {
let r = 1;
for (let i = 2; i <= n; i++) r *= i;
return r;
}</code></pre>
<h2>頻出エラー 5: is not a function</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught TypeError: foo.bar is not a function
Uncaught TypeError: arr.map is not a function ← arr が配列ではない</code></pre><pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ オブジェクトに map を呼んだ
const data = { items: [1,2,3] };
data.map(x => x * 2); // ❌ data は配列ではない
// ✅ 正しいプロパティ
data.items.map(x => x * 2);
// ❌ API レスポンス前提が崩れる
const res = await fetch('/api');
const json = await res.json();
json.results.map(...); // ❌ results が undefined
// ✅ デバッグ
console.log(typeof json.results, json.results);
// → object, undefined etc.
// ✅ Array.isArray() で確認
if (Array.isArray(json.results)) {
json.results.map(...);
}</code></pre>
<h2>頻出エラー 6: Illegal invocation</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Uncaught TypeError: Illegal invocation</code></pre>
<p>主に DOM API のメソッドを <code>this</code> 無しで呼んだ場合。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ コンテキスト消失
const log = console.log; // この時点では問題ない
log('hello'); // OK (たまたま動く)
const qs = document.querySelector;
qs('div'); // ❌ Illegal invocation (this が document でない)
// ✅ bind
const qs = document.querySelector.bind(document);
qs('div'); // OK
// ✅ アロー関数で包む
const qs = (sel) => document.querySelector(sel);</code></pre>
<h2>頻出エラー 7: CORS 関連</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-text">Access to fetch at 'https://api.example.com/foo' from origin
'https://myapp.com' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.</code></pre>
<p>クロスオリジン HTTP リクエストで、サーバが許可ヘッダを返していない。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// クライアント側だけでは解決不能
// サーバが Access-Control-Allow-Origin を返す必要あり
// 開発時の回避策: プロキシ
// Vite (vite.config.js):
export default {
server: {
proxy: {
'/api': 'https://backend.example.com'
}
}
}
// fetch 時の credentials
fetch(url, { credentials: 'include' }); // Cookie 送信、サーバ側で Allow-Credentials 必要
// CORS preflight (OPTIONS) が走るリクエスト:
// - Content-Type が application/json
// - カスタムヘッダ付き
// - PUT/DELETE/PATCH</code></pre>
<h2>頻出エラー 8: Promise / async 関連</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// ❌ Unhandled Promise Rejection
async function getUser(id) {
const res = await fetch(`/api/users/${id}`);
return await res.json();
}
getUser(1); // エラー時、未捕捉警告
// ✅ try/catch
try {
const user = await getUser(1);
} catch (e) {
console.error('Failed to load user:', e);
}
// ✅ .catch
getUser(1)
.then(u => console.log(u))
.catch(e => console.error(e));
// ✅ グローバル捕捉
window.addEventListener('unhandledrejection', e => {
console.error('Unhandled:', e.reason);
});
// ❌ await を忘れる
async function check() {
const ok = isAdmin(user); // Promise を真偽判定 (常に true!)
if (ok) { ... }
}
// ✅
const ok = await isAdmin(user);</code></pre>
<h2>デバッグの定石</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>ツール</th><th>用途</th></tr></thead>
<tbody>
<tr><td>DevTools Console</td><td>エラー / console.log / 対話実行</td></tr>
<tr><td>DevTools Sources (Debugger)</td><td>ブレークポイント、ステップ実行、変数監視</td></tr>
<tr><td>DevTools Network</td><td>HTTP リクエスト確認 (4xx/5xx, CORS)</td></tr>
<tr><td>Source Maps (.map)</td><td>ミニファイ後でも元コードでデバッグ</td></tr>
<tr><td><code>debugger;</code> 文</td><td>コード中でブレーク</td></tr>
<tr><td><code>console.table()</code></td><td>配列/オブジェクトを表形式</td></tr>
<tr><td><code>console.trace()</code></td><td>スタックトレース</td></tr>
<tr><td><code>console.dir()</code></td><td>オブジェクトの構造表示</td></tr>
</tbody>
</table>
<h2>エラーバウンダリ (実運用)</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-javascript">// グローバルエラーハンドラ
window.addEventListener('error', e => {
reportError(e.error); // Sentry / Datadog etc.
});
window.addEventListener('unhandledrejection', e => {
reportError(e.reason);
});
// React のエラーバウンダリ
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, info) {
reportError(error, info);
}
render() {
if (this.state.hasError) return <h1>Something broke.</h1>;
return this.props.children;
}
}</code></pre>
<h2>FAQ</h2>
<p><strong>Q: try/catch で何でも握りつぶしてよい?</strong><br />
A: NG。エラーは原則「想定済み」のものだけ catch。想定外を catch して空で握りつぶすと、後の不具合が見えなくなります。<strong>少なくとも console.error / 監視サービス通知</strong>を残す。</p>
<p><strong>Q: console.log を本番に残してよい?</strong><br />
A: 情報漏えいやパフォーマンスの観点で削除が定石。ビルドツール (terser / webpack) で本番ビルド時に <code>drop_console</code> オプションで自動削除可能。</p>
<p><strong>Q: TypeScript で防げる?</strong><br />
A: 多くは防げます。<code>strict</code> モードで null/undefined チェック必須化 (<code>strictNullChecks</code>)、未定義変数の検出、型不整合の早期発見など。ただし実行時の API レスポンス型までは保証しないので、zod 等で検証推奨。</p>