エラノート エラノート

JavaScript undefinedエラーの原因と対処法

JavaScript undefined エラー解決 デバッグ
広告スペース (article-top)

JavaScriptを書いていると「undefined」という言葉に頻繁に出会います。変数の中身を表示したらundefinedだった、undefinedに対してメソッドを呼び出してエラーになった、という経験は初心者なら誰もが通る道です。この記事ではundefinedが発生する原因と対処法をパターン別に解説します。

undefinedとは

undefinedはJavaScriptの特別な値で、「値が定義されていない」状態を表します。エラーそのものではなく、JavaScriptの正式なデータ型の一つです。

let x;
console.log(x);        // undefined
console.log(typeof x);  // "undefined"

変数を宣言しただけで値を代入していない場合、その変数には自動的にundefinedが入ります。

問題が起きるのは、undefinedの状態でプロパティにアクセスしたりメソッドを呼び出したりしたときです。

let user;
// console.log(user.name);
// TypeError: Cannot read properties of undefined (reading 'name')

パターン1: 変数の初期化忘れ

// NG: 宣言だけで値を入れていない
let username;
console.log(username.length);
// TypeError: Cannot read properties of undefined

// OK: 初期値を設定する
let username = "";
console.log(username.length);  // 0

// OK: 使う前にundefinedチェック
let username;
if (username !== undefined) {
  console.log(username.length);
}

対策: デフォルト値を活用する

// 関数の引数にデフォルト値を設定
function greet(name = "ゲスト") {
  return `こんにちは、${name}さん`;
}

console.log(greet());       // "こんにちは、ゲストさん"
console.log(greet("太郎")); // "こんにちは、太郎さん"

パターン2: オブジェクトのプロパティが存在しない

const user = {
  name: "太郎",
  age: 25,
};

// 存在しないプロパティはundefined
console.log(user.email);  // undefined

// さらに深くアクセスするとエラー
// console.log(user.address.city);
// TypeError: Cannot read properties of undefined

対策: オプショナルチェーン(?.)を使う

const user = {
  name: "太郎",
  age: 25,
};

// オプショナルチェーン: undefinedなら途中で止まる
console.log(user.address?.city);      // undefined(エラーにならない)
console.log(user.contacts?.[0]);      // undefined
console.log(user.getName?.());        // undefined

// Null合体演算子(??)と組み合わせてデフォルト値を設定
const city = user.address?.city ?? "未設定";
console.log(city);  // "未設定"

オプショナルチェーン(?.)はES2020で導入された構文で、undefinedやnullのプロパティにアクセスしてもエラーにならずundefinedを返します。

パターン3: 配列の範囲外アクセス

const colors = ["赤", "青", "緑"];

console.log(colors[0]);  // "赤"
console.log(colors[2]);  // "緑"
console.log(colors[3]);  // undefined(範囲外)
console.log(colors[-1]); // undefined(負のインデックスは使えない)

対策: 配列の長さを確認する

const colors = ["赤", "青", "緑"];

// 範囲チェック
const index = 3;
if (index >= 0 && index < colors.length) {
  console.log(colors[index]);
} else {
  console.log("インデックスが範囲外です");
}

// at()メソッド: 負のインデックスも使える
console.log(colors.at(-1));  // "緑"(最後の要素)
console.log(colors.at(0));   // "赤"

パターン4: 関数の戻り値がない

// NG: returnがないのでundefinedが返る
function add(a, b) {
  const result = a + b;
  // returnを忘れている
}

const sum = add(3, 5);
console.log(sum);  // undefined

// OK: returnで値を返す
function add(a, b) {
  return a + b;
}

const sum = add(3, 5);
console.log(sum);  // 8

配列メソッドでの注意

const numbers = [1, 2, 3, 4, 5];

// forEachは常にundefinedを返す
const result = numbers.forEach((n) => n * 2);
console.log(result);  // undefined

// 新しい配列が欲しいときはmapを使う
const doubled = numbers.map((n) => n * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

forEachmapは似ていますが、forEachは戻り値がなく(undefined)、mapは新しい配列を返します。

パターン5: 非同期処理とundefined

// NG: 非同期処理の結果を同期的に受け取ろうとする
function fetchData() {
  let result;
  fetch("https://api.example.com/data")
    .then((response) => response.json())
    .then((data) => {
      result = data;
    });
  return result;  // undefined(fetchが完了する前にreturnされる)
}

// OK: async/awaitを使う
async function fetchData() {
  const response = await fetch("https://api.example.com/data");
  const data = await response.json();
  return data;  // データが返る
}

非同期処理の結果は、awaitで待つか.then()のコールバック内で処理する必要があります。

undefinedチェックの方法まとめ

let value;

// 方法1: typeof(変数が未宣言でもエラーにならない)
if (typeof value !== "undefined") {
  console.log(value);
}

// 方法2: 厳密等価演算子
if (value !== undefined) {
  console.log(value);
}

// 方法3: nullもまとめてチェック(nullish check)
if (value != null) {
  // undefinedとnullの両方を除外
  console.log(value);
}

// 方法4: オプショナルチェーン(プロパティアクセス時)
console.log(obj?.prop?.nested);

// 方法5: Null合体演算子(デフォルト値の設定)
const name = value ?? "デフォルト値";

場面に応じて使い分けましょう。プロパティアクセスにはオプショナルチェーン、デフォルト値の設定にはNull合体演算子がおすすめです。

undefinedは「バグ」ではなくJavaScriptの仕様ですが、undefinedが原因のTypeErrorは立派なバグです。データがundefinedになりうる箇所では事前にチェックする癖をつけることが、安定したコードを書くための第一歩です。

広告スペース (article-bottom)

あわせて読みたい