JavaScriptのオブジェクト操作でよくあるエラーとその解決策まとめ|初心者でもわかる対処法
生徒
「JavaScriptでオブジェクトを使っていると、よくエラーが出るんですが、どうしてでしょうか?」
先生
「JavaScriptのオブジェクト操作は便利ですが、慣れないとよくあるミスでエラーになることがあります。今日は代表的なエラーとその解決策をわかりやすく説明しますね。」
生徒
「どんなエラーがあるのか、具体的に教えてください!」
先生
「はい、それでは順番に見ていきましょう!」
1. 「undefined」のエラーや値が取れない問題
JavaScriptでオブジェクトのプロパティを取り出そうとしたときに、undefinedが返ってきたり、エラーになったりすることがあります。これは、指定したプロパティが存在しないためです。
例えば、次のようなオブジェクトを考えましょう。
const person = {
name: "太郎",
age: 30
};
console.log(person.address); // undefined と表示される
addressプロパティは存在しないので、値はundefinedになります。この状態でさらに深い階層を参照するとエラーになることもあります。
解決策としては、オプショナルチェーン(?.演算子)を使う方法があります。
console.log(person.address?.city); // undefined と表示されエラーにならない
オプショナルチェーンは「もし途中の値がなければそこで止めてundefinedにする」という便利な機能です。
2. 「TypeError: ○○ is not a function」のエラー
オブジェクトのメソッドを呼び出すときに「○○ is not a function」というエラーが出ることがあります。これは、呼び出そうとしているメソッドが実際には存在しなかったり、関数でない場合に起こります。
例を見てみましょう。
const obj = {
greet: "こんにちは"
};
obj.greet(); // TypeError: greet is not a function
ここでは、greetは文字列なので関数のように呼べずエラーになります。
解決策は、関数かどうか確認するか、メソッドとして正しく定義することです。
const obj = {
greet() {
console.log("こんにちは");
}
};
obj.greet(); // こんにちは と表示される
3. プロパティの上書きや削除で失敗することがある
オブジェクトのプロパティを変更したり削除したりしようとしても、うまくいかない場合があります。特に、constで宣言したオブジェクト自体を再代入しようとするとエラーになります。
const obj = { a: 1 };
obj = { b: 2 }; // エラーになる(再代入はできない)
ただし、constでもオブジェクトの中身の変更は可能です。
const obj = { a: 1 };
obj.a = 10; // OK
delete obj.a; // OK
また、Object.freeze()という関数でオブジェクトを凍結(変更不可)にしている場合はプロパティの変更や削除ができません。
4. プロパティの存在確認でよくあるミス
オブジェクトに特定のプロパティがあるかどうか確認するには、in演算子やhasOwnPropertyメソッドを使いますが、使い方を間違えると誤った結果になることがあります。
// 正しい使い方
if ("name" in person) {
console.log("nameがあります");
}
// 間違った例(プロトタイプもチェックしてしまう)
if (person.hasOwnProperty("name")) {
console.log("nameがあります");
}
ここで注意したいのは、hasOwnPropertyはオブジェクト自身のプロパティだけをチェックしますが、継承されたプロパティは見ません。
実際のコードでどちらを使うかは状況によって判断しましょう。
5. JSONのパースでのエラー
オブジェクト形式のデータを文字列で扱う場合、JSON.parse()で変換しますが、形式が正しくないとエラーが出ます。
const jsonStr = '{"name":"太郎","age":30}';
const obj = JSON.parse(jsonStr); // 正常にオブジェクトになる
const badJsonStr = '{"name":"太郎",age:30}';
const obj2 = JSON.parse(badJsonStr); // SyntaxErrorになる
JSONはキーや文字列を必ずダブルクォーテーション(")で囲む必要があるので注意しましょう。
6. オブジェクトのキーに変な値を使うと意図しない動きに
JavaScriptのオブジェクトのキーは基本的に文字列ですが、他の型を使うと文字列に変換されます。そのため、数字の1と文字列の"1"は同じキーとして扱われます。
const obj = {};
obj[1] = "数字の1";
obj["1"] = "文字列の1";
console.log(obj); // { "1": "文字列の1" }
同じキーとして上書きされるため、意図しない結果になることがあります。キーはなるべく文字列で統一するか、Mapオブジェクトの使用も検討しましょう。
7. 変数名とプロパティ名の混同に注意
オブジェクトのプロパティ名と変数名を間違えて使うと、値が取得できないことがあります。
const name = "太郎";
const person = { name: "花子" };
console.log(name); // 太郎
console.log(person.name); // 花子
console.log(person.Name); // undefined(大文字と小文字は区別される)
JavaScriptは大文字・小文字を区別するので、プロパティ名の綴りも正確に書くことが大切です。
8. プロパティの追加や更新の基本と注意点
オブジェクトに新しいプロパティを追加したり、既存の値を更新するのは簡単ですが、思わぬ影響が出ることもあります。
const obj = { a: 1 };
obj.b = 2; // プロパティbを追加
obj.a = 10; // プロパティaの値を変更
このとき、オブジェクトを他の変数に代入している場合、同じオブジェクトを指しているので、どちらを変更しても影響があります。
const obj1 = { a: 1 };
const obj2 = obj1;
obj2.a = 100;
console.log(obj1.a); // 100 と表示される
これは「参照渡し」と呼ばれ、オブジェクトの特性です。もしコピーしたい場合は、Object.assign()やスプレッド構文を使います。
9. エラーを減らすためのポイントまとめ
- オプショナルチェーン(
?.)を使い、安全にプロパティを取得する - 関数かどうか確認してからメソッドを呼ぶ
constで宣言してもオブジェクトの中身は変更可能- プロパティの存在確認は
in演算子やhasOwnPropertyを使い分ける - JSONの形式に注意して正しい文字列を扱う
- オブジェクトのキーは文字列として扱われることを理解する
- 大文字・小文字は区別されるので正確に書く
- オブジェクトのコピーは浅いコピーで十分か考える
まとめ
ここまでJavaScriptのオブジェクト操作における代表的なエラーや注意点について詳しく解説してきました。オブジェクトはJavaScriptの基幹となるデータ構造であり、Web開発の現場では避けて通れない非常に重要な要素です。配列と並んで最も頻繁に利用されるため、その挙動を深く理解しておくことは、バグの少ないクリーンなコードを書くための第一歩となります。
オブジェクト操作の基本を再確認
JavaScriptのオブジェクトは、キー(プロパティ名)と値(バリュー)のペアで構成されています。この記事で学んだ通り、最も多いトラブルは「存在しないプロパティへのアクセス」です。特に、APIから取得したデータなど、中身が動的に変わるオブジェクトを扱う際には注意が必要です。
例えば、以下のように深くネストされたオブジェクトから安全にデータを抽出する方法を復習しておきましょう。従来のコードと、モダンなJavaScript(ES2020以降)の書き方を比較してみます。
// サンプルデータ
const userData = {
id: 101,
profile: {
userName: "エンジニア志望",
// preferencesプロパティが欠損している可能性がある
}
};
// 昔ながらの安全な書き方(冗長になりがち)
let theme = "default";
if (userData.profile && userData.profile.preferences) {
theme = userData.profile.preferences.theme;
}
// オプショナルチェーン(?.)を使ったモダンな書き方
const modernTheme = userData.profile?.preferences?.theme ?? "default";
console.log("テーマ設定:", modernTheme);
テーマ設定: default
型安全性とTypeScriptの導入検討
JavaScriptは非常に自由度が高い言語ですが、その自由さが原因で、実行時(ランタイム)にエラーが発生することが多々あります。大規模な開発や、複数人でのチーム開発においては、今回紹介したような「プロパティ名のタイポ」や「型違い」を防ぐために、TypeScriptを導入することが一般的になっています。
TypeScriptを使うと、オブジェクトにどのようなプロパティが存在すべきかをあらかじめ定義できるため、コードを書いている最中にエディタがエラーを指摘してくれます。これにより、不毛なデバッグ時間を大幅に削減することが可能です。
interface User {
name: string;
age: number;
isAdmin?: boolean; // 任意項目
}
const user: User = {
name: "佐藤",
age: 25
};
// TypeScriptなら、存在しないプロパティにアクセスしようとするとコンパイル時にエラーが出る
// console.log(user.address); // Property 'address' does not exist on type 'User'.
参照渡しの罠を回避するテクニック
多くの初心者が躓くのが、オブジェクトの「参照渡し」です。変数にオブジェクトを代入しても、それはデータそのものではなく「データの場所(メモリ上の住所)」を共有しているに過ぎません。意図せず元のデータを書き換えてしまわないよう、スプレッド構文などを用いた「コピー(複製)」の技術をマスターしましょう。
const original = { x: 1, y: 2 };
// 参照渡し(同じ実体を指す)
const reference = original;
reference.x = 99;
// スプレッド構文による浅いコピー(新しいオブジェクトを作成)
const shallowCopy = { ...original };
shallowCopy.y = 500;
console.log("オリジナル:", original);
console.log("コピー:", shallowCopy);
オリジナル: { x: 99, y: 2 }
コピー: { x: 99, y: 500 }
このように、JavaScriptの特性を正しく理解し、適切な文法を選択することで、予期せぬ挙動を未然に防ぐことができます。今回紹介した9つのポイントは、どれも実務で即座に役立つものばかりです。エラーが出たときは焦らず、この記事の内容を思い出して、一つずつ原因を特定してみてください。
生徒
「先生、ありがとうございました!オブジェクト操作って一見簡単そうですけど、実は奥が深いんですね。特に『参照渡し』の話を聞いて、今まで自分のコードがなぜ変な動きをしていたのか、やっと理由がわかりました。」
先生
「そうですね。参照渡しは、JavaScriptを学ぶ上で必ず通る壁の一つです。メモリ上の同じ場所を見ているという感覚が掴めれば、もう怖くありませんよ。あとはオプショナルチェーンなども使いこなせていますか?」
生徒
「はい!これまではif (obj && obj.prop)みたいに長く書いていたんですが、?.を使うとすごくスッキリ書けるので驚きました。コードの可読性が全然違いますね。」
先生
「その通りです。モダンな書き方を覚えることで、エラーを防ぐだけでなく、他の開発者が読みやすいコードを書けるようになります。JSONのパースについても、例外処理(try-catch)を組み合わせる癖をつけておくと、さらに堅牢なプログラムになりますよ。」
生徒
「なるほど、外部からのデータを受け取るときは常にエラーの可能性を考えるべきなんですね。あと、TypeScriptの話も気になりました。オブジェクトの形をあらかじめ決めておけるのは、開発がすごく楽になりそうです。」
先生
「いいところに目をつけましたね!JavaScriptの基本が身についたら、ぜひ次はTypeScriptに挑戦してみてください。今日のまとめで解説したようなエラーの多くを、実行前に自動で見つけ出してくれるようになります。習得のコツは、とにかくエラーメッセージをしっかり読むことですよ。」
生徒
「分かりました!まずは今日学んだエラー対策を徹底して、自分のプロジェクトを修正してみます。ありがとうございました!」
先生
「頑張ってくださいね。応援しています!」