タイトル: エラー一覧
SEOタイトル: JavaScript よくあるエラー集と対処
| この記事の要点 |
|
JavaScript エラーの分類
JavaScript のエラーは大きくシンタックスエラー (構文エラー) と実行時エラーに分かれます。実行時エラーは Error オブジェクトを継承した複数のサブクラスがあります。
| クラス | 意味 | 典型例 |
|---|---|---|
| SyntaxError | 構文として不正 | 括弧の閉じ忘れ、JSON.parse 失敗 |
| TypeError | 値の型が予期しない | undefined のプロパティアクセス、関数でないものを呼ぶ |
| ReferenceError | 定義されていない変数 | スペルミス、TDZ、グローバル参照 |
| RangeError | 範囲外の値 | 再帰深すぎ、Array 長過剰 |
| URIError | URI 関数の不正 | decodeURI('%') |
| EvalError | eval の不正 (現在ほぼ未使用) | - |
| AggregateError | 複数エラー集約 | Promise.any 全 reject |
頻出エラー 1: Cannot read properties of undefined
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')
最頻出エラー。undefined または null の値に対してプロパティ / メソッドアクセスしようとした場合に発生。
// ❌ よくある原因
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(...); // 空でも安全
頻出エラー 2: x is not defined
Uncaught ReferenceError: foo is not defined
Uncaught ReferenceError: $ is not defined ← jQuery が読まれていない
Uncaught ReferenceError: process is not defined ← ブラウザで Node 変数を使った
存在しない変数を参照した場合に発生。
// ❌ スペルミス
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 後に実行
頻出エラー 3: Unexpected token
Uncaught SyntaxError: Unexpected token '}'
Uncaught SyntaxError: Unexpected token in JSON at position 0
Uncaught SyntaxError: Unexpected end of JSON input// ❌ 括弧 / カンマ不一致
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;
}
}
頻出エラー 4: Maximum call stack size exceeded
Uncaught RangeError: Maximum call stack size exceeded// ❌ 無限再帰
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;
}
頻出エラー 5: is not a function
Uncaught TypeError: foo.bar is not a function
Uncaught TypeError: arr.map is not a function ← arr が配列ではない// ❌ オブジェクトに 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(...);
}
頻出エラー 6: Illegal invocation
Uncaught TypeError: Illegal invocation
主に DOM API のメソッドを this 無しで呼んだ場合。
// ❌ コンテキスト消失
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);
頻出エラー 7: CORS 関連
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.
クロスオリジン HTTP リクエストで、サーバが許可ヘッダを返していない。
// クライアント側だけでは解決不能
// サーバが 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
頻出エラー 8: Promise / async 関連
// ❌ 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);
デバッグの定石
| ツール | 用途 |
|---|---|
| DevTools Console | エラー / console.log / 対話実行 |
| DevTools Sources (Debugger) | ブレークポイント、ステップ実行、変数監視 |
| DevTools Network | HTTP リクエスト確認 (4xx/5xx, CORS) |
| Source Maps (.map) | ミニファイ後でも元コードでデバッグ |
debugger; 文 | コード中でブレーク |
console.table() | 配列/オブジェクトを表形式 |
console.trace() | スタックトレース |
console.dir() | オブジェクトの構造表示 |
エラーバウンダリ (実運用)
// グローバルエラーハンドラ
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;
}
}
FAQ
Q: try/catch で何でも握りつぶしてよい?
A: NG。エラーは原則「想定済み」のものだけ catch。想定外を catch して空で握りつぶすと、後の不具合が見えなくなります。少なくとも console.error / 監視サービス通知を残す。
Q: console.log を本番に残してよい?
A: 情報漏えいやパフォーマンスの観点で削除が定石。ビルドツール (terser / webpack) で本番ビルド時に drop_console オプションで自動削除可能。
Q: TypeScript で防げる?
A: 多くは防げます。strict モードで null/undefined チェック必須化 (strictNullChecks)、未定義変数の検出、型不整合の早期発見など。ただし実行時の API レスポンス型までは保証しないので、zod 等で検証推奨。