JavaScript 入門

JS オブジェクト作成

JavaScriptは多機能なプログラミング言語であり、コード内で複雑な現実世界のエンティティをシミュレートすることを可能にします。

私たちはすでに基本的なデータ型(数値、文字列、ブール値など)や、配列のようなコレクションについて学習してきましたが、複数の異なる特徴や振る舞いを持つものを表現する場合、これらだけでは不十分なことがよくあります。

そこで登場するのが オブジェクト (Objects) です。オブジェクトは、関連するデータと機能を一つの緊密に連結されたユニットにまとめるための基本的なビルドブロックです。これは、現実世界の物品が特定の属性を持ち、実行可能なアクションを持っているのと似ています。

これらのオブジェクトをどのように作成し、プロパティ (Properties) を定義し、メソッド (Methods) という振る舞いを割り当てるかを理解することは、より整理され、強力で、読みやすいJavaScriptコードを書くために不可欠です。

1. オブジェクトの理解:プロパティとメソッド

JavaScriptにおいて、オブジェクトはプロパティと型を持つ独立したエンティティです。オブジェクトは、一つのコンセプトに関連する様々な情報(データ)と特定のアクション(機能)を収める「コンテナ」だと考えることができます。

このコンセプトは、人間、車、本、あるいはアプリケーションの設定項目など、何でもあり得ます。

2. オブジェクトリテラルを使用したオブジェクトの作成

JavaScriptでオブジェクトを作成する最も一般的で直接的な方法は、オブジェクトリテラル (Object Literal) を使用することです。オブジェクトリテラルは、中括弧 {} で囲まれた、カンマ区切りの「名前と値」のペア(つまりプロパティ)の集合体です。

constlet を使用してオブジェクトを宣言すると、本質的にはメモリ内にそのオブジェクトへの参照を作成していることになります。

// 「人」を表す基本的なオブジェクトリテラル
const person = {
  // プロパティをここに記述
};

// 「製品」を表す基本的なオブジェクトリテラル
let product = {
  // プロパティをここに記述
};

この構文はシンプルで直感的であり、単一のオブジェクトインスタンスを作成するために広く利用されています。

3. プロパティの定義

プロパティ (Properties) はオブジェクトの特徴や特性です。これらは「キーと値 (Key-Value)」のペアであり、キー (Key)(プロパティ名とも呼ばれる)は通常そのデータを表す文字列で、値 (Value) が実際のデータとなります。

値には、これまでに紹介したあらゆるJavaScriptのデータ型を使用できます:数値、文字列、ブール値、配列、さらには別のオブジェクトも可能です。

3.1 プロパティの構文

propertyName: value

propertyName(プロパティ名)は通常、識別子(firstName, age など)ですが、スペースや特殊文字が含まれる場合は引用符で囲む必要があります(例: "first name")。シンプルかつベストプラクティスに従うなら、スペースや特殊文字を含まない識別子に適した名称を使用することをお勧めします。

3.2 プロパティを持つオブジェクトの例

学生を表現する場合を考えてみましょう。学生は名前、ID、成績、そして登録しているコースのリストを持っているかもしれません。

const student = {
  firstName: "アリス",     // 文字列プロパティ
  lastName: "スミス",      // 文字列プロパティ
  studentId: 101,         // 数値プロパティ
  isEnrolled: true,       // ブール値プロパティ
  grade: 92.5,            // 数値プロパティ
  courses: ["数学", "科学", "歴史"], // 配列プロパティ
  address: {              // オブジェクトプロパティ (入れ子になったオブジェクト)
    street: "メインストリート 123号",
    city: "エニーシティ",
    zipCode: "12345"
  }
};

console.log(student);
/* 出力:
{
  firstName: 'アリス',
  lastName: 'スミス',
  studentId: 101,
  isEnrolled: true,
  grade: 92.5,
  courses: [ '数学', '科学', '歴史' ],
  address: { street: 'メインストリート 123号', city: 'エニーシティ', zipCode: '12345' }
}
*/

この student オブジェクトにおいて:

  • firstNamelastNamestudentIdisEnrolledgradecourses はすべてプロパティです。
  • それらの値は異なるデータ型(文字列、数値、ブール値、配列)です。
  • address もプロパティですが、その値は 別のオブジェクト です。これは、オブジェクトを入れ子にすることで、より複雑な関係を表現できることを示しています。

もう一つの例として、図書館にある「本」を表現してみましょう。

const book = {
  title: "JavaScript 冒険記",
  author: "J.S. Developer",
  publicationYear: 2023,
  pageCount: 450,
  isAvailable: true,
  genres: ["プログラミング", "教育"]
};

console.log(book);
/* 出力:
{
  title: 'JavaScript 冒険記',
  author: 'J.S. Developer',
  publicationYear: 2023,
  pageCount: 450,
  isAvailable: true,
  genres: [ 'プログラミング', '教育' ]
}
*/

ここでは、titleauthorpublicationYearpageCountisAvailablegenres が、book オブジェクトの異なる側面を定義するプロパティとなっています。

4. メソッドの定義

プロパティがオブジェクトの「状態」を表すなら、メソッドはオブジェクトが「何ができるか」を表します。

メソッド (Methods) とは、オブジェクトのプロパティとして保存された関数のことです。通常の関数と同様に、メソッドはアクションを実行し、引数を受け取り、値を返すことができます。決定的な違いは、それらがオブジェクトに本質的に関連付けられている点です。

4.1 メソッドの構文

関数式をプロパティの値として使用してメソッドを定義できます:

methodName: function(parameters) {
  // メソッド本体
}

または、よりモダンで簡潔なメソッド構文(ES6+)を使用することもでき、通常はこちらが推奨されます:

methodName(parameters) {
  // メソッド本体
}

4.2 メソッドを持つオブジェクトの例

先ほどの student オブジェクトを拡張して、自己紹介をするメソッドを追加してみましょう。

const student = {
  firstName: "アリス",
  lastName: "スミス",
  studentId: 101,
  isEnrolled: true,
  grade: 92.5,
  courses: ["数学", "科学", "歴史"],
  
  // 学生が自己紹介をするメソッド
  introduce: function() {
    console.log("こんにちは、私の名前は " + this.firstName + " " + this.lastName + " です。");
    // 注:`this` キーワードについては後のレッスンで詳しく説明します。
    // 現時点では、`this.firstName` が「この」オブジェクトの `firstName` プロパティを指すと理解してください。
  }
};

// メソッドを呼び出すには、ドット記法に続けて括弧を使用します
student.introduce(); // 出力: こんにちは、私の名前は アリス スミス です。

この例では、introducestudent オブジェクトのメソッドです。呼び出されると、オブジェクト自身のプロパティを使用してアクション(コンソールへのメッセージ表示)を実行します。

算術演算を行う 計算機 (calculator) オブジェクトの例も見てみましょう。

const calculator = {
  // プロパティ (オプションだが、現在の結果を保存するために使用可能)
  currentResult: 0,

  // 2つの数値を足すメソッド
  add: function(num1, num2) {
    this.currentResult = num1 + num2;
    console.log("加算結果: " + this.currentResult);
    return this.currentResult;
  },

  // 2つの数値を引くメソッド (簡潔なメソッド構文を使用)
  subtract(num1, num2) {
    this.currentResult = num1 - num2;
    console.log("減算結果: " + this.currentResult);
    return this.currentResult;
  },

  // 2つの数値を掛けるメソッド
  multiply: (num1, num2) => { // アロー関数構文も使用可能
    // 注意:アロー関数内での `this` の使用には注意が必要です(後述)
    // デモのために記述していますが、通常オブジェクトメソッドでは `this` を正しく指すために前の2つの書き方が推奨されます
    console.log("乗算ロジックのデモ");
  },

  // 現在保存されている結果を取得するメソッド
  getResult() {
    return this.currentResult;
  }
};

// メソッドの呼び出し
calculator.add(5, 3);      // 出力: 加算結果: 8
calculator.subtract(10, 4); // 出力: 減算結果: 6
console.log("現在の結果: " + calculator.getResult()); // 出力: 現在の結果: 6

ここで、addsubtractgetResultcalculator オブジェクトのメソッドです。これらは異なる算術演算のロジックをカプセル化し、オブジェクトの内部状態(currentResult)と対話することができます。

例の中で使用されている this キーワード(例: this.firstName, this.currentResult)は、オブジェクト自体を指します。メソッドが呼び出されると、そのメソッド内部の this はそのメソッドを「所有」しているオブジェクトを指します。これにより、メソッドはオブジェクトのプロパティにアクセスし、変更することが可能になります。this については今後のレッスンで深く掘り下げますが、今は「所属するオブジェクトのデータと対話するためのもの」と覚えておいてください。

5. 実戦的な例とデモンストレーション

プロパティとメソッドを組み合わせて、車 (Car) を表すより包括的なオブジェクトを構築してみましょう。

// プロパティとメソッドを含む Car オブジェクトを定義
const myCar = {
  make: "トヨタ",
  model: "カムリ",
  year: 2020,
  color: "シルバー",
  mileage: 50000,
  isRunning: false, // 初期状態

  // エンジンを始動するメソッド
  start: function() {
    if (!this.isRunning) {
      this.isRunning = true;
      console.log(`${this.make} ${this.model} が始動しました。`);
    } else {
      console.log(`${this.make} ${this.model} はすでに動いています。`);
    }
  },

  // エンジンを停止するメソッド
  stop() { // 簡潔なメソッド構文を使用
    if (this.isRunning) {
      this.isRunning = false;
      console.log(`${this.make} ${this.model} が停止しました。`);
    } else {
      console.log(`${this.make} ${this.model} はすでに停止しています。`);
    }
  },

  // 走行して走行距離を増やすメソッド
  drive(distance) {
    if (this.isRunning) {
      this.mileage += distance;
      console.log(`${distance} マイル走行しました。総走行距離: ${this.mileage}`);
    } else {
      console.log(`走行できません。${this.make} ${this.model} のエンジンがかかっていません。`);
    }
  },

  // 車の情報を取得するメソッド
  getInfo: function() {
    return `これは ${this.year} 年製の ${this.make} ${this.model} です。色は${this.color}、走行距離は ${this.mileage} マイルです。現在は${this.isRunning ? '走行中' : '停止中'}です。`;
  }
};

console.log("--- 初期の車の状態 ---");
console.log(myCar.getInfo()); 
// 出力: これは 2020 年製の トヨタ カムリ です。色はシルバー、走行距離は 50000 マイルです。現在は停止中です。

console.log("\n--- エンジン始動 ---");
myCar.start();              // 出力: トヨタ カムリ が始動しました。
console.log(myCar.getInfo()); // 出力: ...現在は走行中です。

console.log("\n--- 再度の始動試行 ---");
myCar.start();              // 出力: トヨタ カムリ はすでに動いています。

console.log("\n--- 走行 ---");
myCar.drive(100);           // 出力: 100 マイル走行しました。総走行距離: 50100
myCar.drive(50);            // 出力: 50 マイル走行しました。総走行距離: 50150
console.log(myCar.getInfo()); // 出力: ...走行距離は 50150 マイルです。

console.log("\n--- エンジン停止 ---");
myCar.stop();               // 出力: トヨタ カムリ が停止しました。
console.log(myCar.getInfo()); // 出力: ...現在は停止中です。

console.log("\n--- 停止中の走行試行 ---");
myCar.drive(20);            // 出力: 走行できません。トヨタ カムリ のエンジンがかかっていません。

この総合的な myCar オブジェクトは、プロパティ(make, model, mileage など)がいかにデータを保持し、メソッド(start, stop, drive, getInfo)がいかにそのデータに関連するアクションやロジックをカプセル化するかを完璧に示しています。これらのメソッドはオブジェクトのプロパティ(isRunning, mileage)を修正し、現在の状態に応じて振る舞いを変化させています。