【JavaScript】オブジェクトに新しい要素を追加する方法を初心者向けにわかりやすく解説

はじめに

JavaScriptを使ってプログラミングを始めると、オブジェクトという言葉をよく耳にするのではないでしょうか。 多くの場面で登場するため、その概念を理解しておくことは大切です。 特にオブジェクトに新しい情報を追加する処理はよく使われます。 たとえば、ユーザーデータや設定データなど、最初は一定の構造をもったオブジェクトが用意されることが多いです。 そこに動的に情報を加えていくケースがあるため、「どのようにプロパティを追加すればよいのか」を知っておけば、困る場面が格段に減ります。

今回は、JavaScriptでオブジェクトに新しい要素を追加する方法を初心者の方にも読みやすいように解説していきます。 サンプルコードをまじえながら、具体的な活用場面に落とし込んで考えてみます。 少しでも実務のイメージを抱きやすいようにするのが狙いです。

この記事を読むとわかること

  • JavaScriptオブジェクトとは何か
  • オブジェクトにプロパティを追加する方法(ドット記法・ブラケット記法など)
  • プロパティ追加時に気を付けるポイントや上書きリスク
  • プロトタイプチェーンの仕組みと、独自に追加する場合の注意点
  • 実務での活用シーン(ユーザーデータ、フォーム入力など)との関連
  • TypeScriptで型を扱う際の注意点

JavaScriptのオブジェクトとは何か

JavaScriptでは、配列や関数を含め、ほとんどのものがオブジェクトとして扱われます。 しかし、ここでは主にオブジェクトリテラルという形で記述される、いわゆる {} で囲まれたデータ構造を取り上げます。

オブジェクトの基本

オブジェクトとは、複数の情報をキーと値の組み合わせ(プロパティ)で管理できる仕組みです。 たとえば、ユーザー情報をオブジェクトで表すと、名前や年齢、メールアドレスなどをひとまとめに管理できます。 配列とは違い、インデックス(添字)ではなくキー名でアクセスする点が特徴です。

具体的には以下のように書きます。

const user = {
  name: "Tanaka",
  age: 28
};

このように、nameage などの「キー(プロパティ名)」と「値」をセットで管理します。 オブジェクトを使うと、プログラム内で関連するデータを整理しやすくなるでしょう。

オブジェクトリテラル

先ほどの例のように、{} の中にプロパティを記述して定義する方法をオブジェクトリテラルと呼びます。 いくつかの変数をまとめて管理できるため、コードの見通しをよくするのに役立ちます。

たとえば、設定情報をオブジェクトにまとめたい場合は、以下のようにすると便利です。

const config = {
  title: "My Awesome App",
  theme: "dark",
  lang: "ja"
};

これはアプリケーション全体で共通して使う設定をひとつにまとめた例です。 このように、さまざまな場面でオブジェクトが活躍します。

プロパティとメソッド

オブジェクトの中には、プロパティと呼ばれる値のほかに、メソッドという関数を入れることもできます。 メソッドとは簡単に言えば「オブジェクトにひも付いた関数」のことです。

例として、以下のコードを見てください。

const user = {
  name: "Tanaka",
  age: 28,
  greet: function() {
    console.log("こんにちは!");
  }
};

user.greet(); // "こんにちは!" と表示される

greet というキーには関数が紐づいており、 user.greet() のように実行するとメソッドとして動作します。 これらは後から追加することも可能です。

オブジェクトにプロパティを追加する方法

ここからは、本題である「オブジェクトにプロパティを追加する具体的な手法」について解説します。 オブジェクトを定義したあとに新しい情報を付け加える場面は日常的に発生するので、ぜひ押さえておきたいポイントです。

ドット記法

もっとも基本的な方法が、ドット記法(プロパティアクセスのドット構文)を使うやり方です。 すでに存在するオブジェクトに対して、ドット記法で新しいキーと値を指定すると、簡単に追加できます。

const user = {
  name: "Tanaka",
  age: 28
};

// 新しいプロパティを追加
user.email = "tanaka@example.com";

console.log(user.email); // "tanaka@example.com"

ドットの右側に書いた email というキーが存在しなかった場合、自動的に新しいプロパティが作られて値が設定されます。 もしすでに同じキーが存在した場合は、上書きされる点に注意が必要です。

ブラケット記法

次に、ブラケット記法[] を使うアクセス方法)です。 ドット記法と似ていますが、文字列や変数を使ってプロパティを追加・アクセスできるのが特徴です。

const user = {
  name: "Tanaka",
  age: 28
};

// 文字列で追加する場合
user["address"] = "Tokyo";

// 変数を使う場合
const propKey = "phone";
user[propKey] = "090-1234-5678";

console.log(user.address); // "Tokyo"
console.log(user.phone);   // "090-1234-5678"

上記のように、ドット記法では使えない文字列(スペースやハイフンを含む場合など)をプロパティ名にしたいときや、変数からキーを動的に作成したいときに便利です。 また、動的にキーを決定するケース(APIから取得したキー名をそのまま使う等)でも重宝します。

computed property name

ES2015(ES6)以降では、オブジェクトリテラルの作成時にも計算されたプロパティ名(computed property name)を使えます。 これは、オブジェクトを定義する段階で変数をキー名として利用できる仕組みです。

const keyName = "email";
const user = {
  name: "Tanaka",
  [keyName]: "tanaka@example.com"
};

console.log(user.email); // "tanaka@example.com"

このように、ブラケット記法と似た感覚で、オブジェクトリテラルの段階から動的なキーを設定できます。 追加というよりは最初から動的にプロパティを決める場合に役立ちます。

Object.assign() を使う方法

既存のオブジェクトに対して、複数のプロパティをまとめて追加したい場合は、Object.assign() が選択肢になります。 Object.assign() は最初の引数にターゲットオブジェクトを取り、2番目以降の引数として追加したいプロパティを含むオブジェクトを指定します。

const user = {
  name: "Tanaka",
  age: 28
};

const additional = {
  email: "tanaka@example.com",
  phone: "090-1234-5678"
};

// user オブジェクトに、additionalオブジェクトのプロパティをまとめて追加
Object.assign(user, additional);

console.log(user);
// { name: "Tanaka", age: 28, email: "tanaka@example.com", phone: "090-1234-5678" }

追加やマージと呼ばれる操作がまとめてできるため、構造が似たオブジェクト同士を合体したいような場面で使われます。 ただし、同じキーが含まれている場合は上書きになるので注意してください。

スプレッド構文を使う方法

スプレッド構文(...)を使った書き方は、オブジェクトをコピーしつつ追加や上書きを行う場面でよく利用されます。 新しいオブジェクトを生成する形なので、もとのオブジェクトを直接書き換えたくないときに有用です。

const user = {
  name: "Tanaka",
  age: 28
};

const newUser = {
  ...user,
  email: "tanaka@example.com",
  phone: "090-1234-5678"
};

console.log(newUser);
// { name: "Tanaka", age: 28, email: "tanaka@example.com", phone: "090-1234-5678" }

console.log(user);
// { name: "Tanaka", age: 28 } (元のオブジェクトは変わらない)

この方法では、user の元の内容をコピーしつつ、emailphone のような新しいプロパティを追加できます。 もしすでに email などのプロパティが存在していれば、上書きされます。

開発現場で役立つオブジェクトの追加活用シーン

オブジェクトに新しいプロパティを追加する場面は、実務でも頻繁に登場します。 具体的なシーンを思い浮かべながら、どう応用できるかを考えてみましょう。

シーン1: ユーザーデータの拡張

たとえば、ユーザーログイン機能があり、ログイン後に取得したユーザーデータをもとに画面を表示するとします。 最初は名前やメールアドレスしかなかったのに、後から「誕生日」や「性別」などの追加項目が必要になるケースがあります。 このとき、オブジェクトに対して以下のようにプロパティを追加していくことになるでしょう。

const user = {
  name: "Tanaka",
  email: "tanaka@example.com"
};

// 後から誕生日情報を付与
user.birthday = "1995-05-10";
user.gender = "male";

こうした手軽な拡張が、オブジェクトを利用する大きなメリットです。

シーン2: フロントエンドとバックエンドのデータ受け渡し

フロントエンドのJavaScript側で、サーバーから受け取ったJSONデータをさらに加工して画面に表示することは多いです。 たとえば、サーバーが返してくれたデータに 新しいプロパティ を付与してビューに渡す、という流れがあります。

// 例: サーバーが返したユーザーデータ
const userDataFromServer = {
  name: "Suzuki",
  age: 30
};

// アプリ固有のフラグやIDを付与してから画面に渡す
userDataFromServer.isActive = true;
userDataFromServer.tempId = "user-001";

renderUserProfile(userDataFromServer);

画面の切り替えや、状態管理の段階で新しいフィールドを使いたい場合に、このような処理が便利です。

シーン3: 動的に生成されるフォーム入力

フォーム入力項目がユーザーの操作によって可変になるようなケースでは、ユーザーが追加した項目をオブジェクトにまとめて保管したい場面もあります。 例えば、趣味や特技を複数登録できるフォームを想定してみてください。 ユーザーが趣味を1つ追加するたびに、オブジェクトに加えていくイメージです。

const formData = {
  name: "Yamada",
  hobbies: []
};

// ユーザーが趣味を追加
formData.hobbies.push("reading");
formData.hobbies.push("cooking");

このように、「どのプロパティを持つか分からないけれど、ユーザーの操作次第でどんどん追加していく」という場面でも役立ちます。

プロパティ追加における注意点

オブジェクトにプロパティを追加することは便利ですが、いくつか注意しておきたいポイントがあります。 特に上書きリスクや動的キーの衝突などは、開発初期には起こりがちなので、しっかり意識しておきましょう。

上書きリスク

前述の通り、同じキー名のプロパティがすでに存在した場合、新しく追加しているつもりが上書きしてしまう可能性があります。 一度上書きすると以前の値は失われるため、意図せずデータを消してしまうことになるかもしれません。

const user = { name: "Tanaka", email: "old@example.com" };
user.email = "new@example.com"; // 上書き

開発中は予期しないキー名の重複が起きる場合があるので、変数名やキー名の選択、利用する関数の設計を注意深く進める必要があります。

動的キーと予期せぬ衝突

外部APIから受け取ったデータをそのままオブジェクトにマージするような場合、キー名が何になるかがわからないことがあります。 その結果、自分で既に使っているキー名と衝突し、上書きを発生させてしまうかもしれません。

たとえば、以下のケースです。

const user = { id: 1, name: "Tanaka" };
const apiResponse = { id: 2, email: "tanaka@example.com" };

// 2つを合体しようとしたら、id が衝突して上書きになる
Object.assign(user, apiResponse);

console.log(user);
// { id: 2, name: "Tanaka", email: "tanaka@example.com" }

もとのidが 1 だったものが 2 に上書きされてしまいました。 こういった想定外の衝突を防ぎたいときは、キー名を整理したり、別のプロパティを用意したり、マージ前に変換処理を入れたりする対策が必要です。

パフォーマンスに関する考慮

JavaScriptエンジンは、オブジェクトの形状(どのプロパティがどれだけあるか)をある程度最適化して管理しています。 それを頻繁に動的に変更すると、内部的な再最適化が発生してパフォーマンスに影響が出る可能性があります。

通常のアプリケーションでは大きな問題にならないことが多いですが、高速処理が求められる場面では、極端な動的変更を避ける設計が望まれます。

特に大量のデータに対してオブジェクトを生成し、プロパティを頻繁に追加・削除する場合は、注意が必要です。

プロトタイプチェーンを意識した追加と挙動

JavaScriptでは、各オブジェクトがプロトタイプと呼ばれる別のオブジェクトを参照する仕組みを持っています。 これによって、あるオブジェクトから継承したプロパティやメソッドにアクセスできるようになります。

プロトタイプチェーンとは

プロトタイプチェーンは、「自分のオブジェクトにないプロパティが呼ばれたときに、上位のオブジェクト(プロトタイプ)をたどって探す」という仕組みです。 そのため、自分が所有していないプロパティでも、継承元のオブジェクトに定義されていれば利用できます。

たとえば、ArrayObject などのビルトインオブジェクトは、共通のメソッドをプロトタイプ経由で継承しています。

自分が作成したインスタンスオブジェクトへのプロパティ追加

たとえば、以下のようにコンストラクタ関数を使って自前のオブジェクトを作成したとします。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log("Hello! My name is " + this.name);
};

const p1 = new Person("Tanaka");
p1.greet(); // "Hello! My name is Tanaka"

p1 のオブジェクト自体には、name プロパティだけが定義されていますが、 p1.greet() を実行すると、プロトタイプに定義された greet メソッドを呼び出しているわけです。

もし p1 に新たなプロパティを直接追加したい場合は、先ほど解説したドット記法などを使えばOKです。

p1.age = 28;
console.log(p1.age); // 28

これは p1 インスタンスそのものに追加しただけであり、プロトタイプに変更は加わりません。

ビルトインオブジェクトへの拡張は避ける

JavaScriptでは、StringArray などのビルトインオブジェクト(組み込みオブジェクト)のプロトタイプを直接書き換えることもできます。 しかし、これは推奨されません。

// 例:Arrayのプロトタイプに独自メソッドを追加
Array.prototype.firstItem = function() {
  return this[0];
};

このような書き方をすると、全ての配列オブジェクトfirstItem メソッドを持つようになり、影響範囲が広くなりすぎてデバッグが困難になります。 予期せぬ挙動を引き起こすリスクが高いため、ビルトインオブジェクトへの直接的な拡張は避けましょう。

TypeScriptでの補足

ここまでJavaScriptだけを前提としてきましたが、TypeScriptを使って開発する場合は、型定義が追加される点が大きく異なります。 そのため、オブジェクトにプロパティを追加する操作にも注意が必要です。

型定義でエラーを回避する

TypeScriptでは、あらかじめオブジェクトに持たせるプロパティを定義しておくと、その型に含まれないプロパティを追加しようとした際にエラーになります。 たとえば、以下のような型を定義したとします。

type User = {
  name: string;
  age: number;
};

const user: User = {
  name: "Tanaka",
  age: 28
};

// user.email = "tanaka@example.com"; // エラー: Property 'email' does not exist on type 'User'.

このように、User 型を定義していると email プロパティが想定されていないのでエラーが起きます。 もし追加する可能性があるなら、email?: string; のようにオプショナルプロパティを追加しておくか、インデックスシグネチャを利用する手段もあります。

インデックスシグネチャの活用

「外部から来る予測できないキーをそのまま受け取りたい」というときには、インデックスシグネチャを使う方法があります。 インデックスシグネチャを使うと、以下のように「任意のキー(文字列)に対して、どんな型でも受け付ける」といった定義ができます。

type FlexibleUser = {
  name: string;
  age: number;
  [key: string]: any;
};

const user: FlexibleUser = {
  name: "Tanaka",
  age: 28
};

user.email = "tanaka@example.com"; // OK

これにより、設計上、どうしても動的なキーを追加する場面でもコンパイルエラーを避けられます。 ただし、あまり乱用すると型の恩恵が薄れるので、必要な場面を見極めて活用するといいでしょう。

まとめ

オブジェクトはJavaScriptの中心的なデータ構造であり、開発のあらゆる場面で使われます。 特に後からプロパティを追加する操作は、本格的なアプリケーションであれば頻繁に登場するでしょう。

  • ドット記法ブラケット記法を使う基本的な方法
  • Object.assign() でまとめて追加する方法
  • スプレッド構文でコピーしつつ追加・上書きする方法

これらを柔軟に使い分けると、管理しやすくなります。

一方で、同じキーがすでに存在した場合に上書きしてしまうリスクや、外部データによる衝突には注意が必要です。 プロパティの追加や上書きが起こりうるコードを書くときは、想定外の動作が発生しないように設計面での工夫が求められます。

ビルトインオブジェクトへのプロトタイプ拡張は、予期しない影響を及ぼすため推奨されません。

このようなリスクを把握しつつ、JavaScriptオブジェクトの柔軟性をうまく活かしてプログラムを組み立ててみてください。 初心者の皆さんは、まずはドット記法・ブラケット記法でオブジェクトに追加するパターンに慣れるところから始めると良いでしょう。

今後、TypeScriptなどで型を扱う場面に進んだ際には、改めて型定義やインデックスシグネチャを活用するかどうかを検討してみてください。 そうすることで、より大規模なプロジェクトでも安心してプロパティの追加を行えるはずです。

JavaScriptをマスターしよう

この記事で学んだJavaScriptの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。