JavaScriptのアクセス指定子を使った関数設計の完全ガイド

JavaScriptでコードを整理し、保守性を高めるための重要な要素の一つがアクセス指定子の使用です。アクセス指定子を利用することで、関数や変数の公開範囲を制御し、意図しない利用を防ぐことができます。本記事では、JavaScriptにおけるアクセス指定子の基本概念から、具体的な使用方法、実例、そしてベストプラクティスまでを詳しく解説します。これにより、あなたのJavaScriptプロジェクトがより安全で効率的に管理できるようになるでしょう。

目次

アクセス指定子とは

アクセス指定子は、オブジェクト指向プログラミングにおいて、クラス内のメンバー(プロパティやメソッド)へのアクセス権を制御するための機能です。これにより、クラスの外部からアクセスできる部分と内部に限定される部分を明確に分けることができます。

アクセス指定子の重要性

アクセス指定子を使用する主な理由は次のとおりです:

カプセル化の実現

カプセル化とは、データを保護し、そのデータを操作するメソッドを外部から隠すことです。これにより、クラスの内部構造を隠蔽し、外部からの不正なアクセスや改変を防ぎます。

コードの保守性向上

アクセス指定子を適切に使用することで、コードの保守性が向上します。外部からアクセスできる部分が明確になるため、修正や機能追加の際に影響範囲を把握しやすくなります。

予期しない動作の防止

アクセス指定子を使って公開範囲を制限することで、意図しない操作や不正なデータ変更を防止できます。これにより、コードの信頼性が高まります。

アクセス指定子の基本概念を理解することで、より安全で効率的な関数設計が可能になります。次のセクションでは、JavaScriptにおける具体的なアクセス指定子の種類について詳しく説明します。

JavaScriptにおけるアクセス指定子の種類

JavaScriptでは、クラスやオブジェクトのメンバーに対してアクセス指定子を使用してアクセス権を制御することができます。以下に、JavaScriptで使用可能な主なアクセス指定子を紹介します。

パブリック

パブリックメンバーは、クラスの外部からアクセス可能です。デフォルトでは、JavaScriptのすべてのプロパティとメソッドはパブリックとして扱われます。

class MyClass {
  constructor() {
    this.publicProperty = "I am public";
  }
  publicMethod() {
    console.log(this.publicProperty);
  }
}

const obj = new MyClass();
console.log(obj.publicProperty); // "I am public"
obj.publicMethod(); // "I am public"

プライベート

プライベートメンバーは、クラスの外部からはアクセスできません。プライベートメンバーは、先頭にシャープ(#)を付けて定義します。

class MyClass {
  #privateProperty = "I am private";

  getPrivateProperty() {
    return this.#privateProperty;
  }
}

const obj = new MyClass();
console.log(obj.getPrivateProperty()); // "I am private"
console.log(obj.#privateProperty); // エラー: プライベートプロパティにはアクセスできません

プロテクテッド(擬似的)

JavaScriptには公式なプロテクテッド(protected)指定子はありませんが、慣習的にアンダースコア(_)を使用して、クラス内部やサブクラスからのみアクセスされるべきメンバーを示すことがあります。

class MyClass {
  _protectedProperty = "I am pseudo-protected";

  getProtectedProperty() {
    return this._protectedProperty;
  }
}

class SubClass extends MyClass {
  accessProtectedProperty() {
    return this._protectedProperty;
  }
}

const obj = new SubClass();
console.log(obj.getProtectedProperty()); // "I am pseudo-protected"
console.log(obj.accessProtectedProperty()); // "I am pseudo-protected"

これらのアクセス指定子を理解し、適切に使用することで、JavaScriptのクラス設計がより安全で明確になります。次のセクションでは、プライベートメソッドの定義方法とその利点について詳しく説明します。

プライベートメソッドの定義

プライベートメソッドは、クラスの外部からはアクセスできないメソッドです。JavaScriptでは、プライベートメソッドを定義するために、メソッド名の前にシャープ(#)を付けます。これにより、そのメソッドはクラス内でのみ使用可能となり、外部からの直接アクセスを防ぎます。

プライベートメソッドの定義方法

プライベートメソッドは、以下のようにクラス内で定義します。

class MyClass {
  #privateMethod() {
    console.log("This is a private method");
  }

  publicMethod() {
    this.#privateMethod();
  }
}

const obj = new MyClass();
obj.publicMethod(); // "This is a private method"
obj.#privateMethod(); // エラー: プライベートメソッドにはアクセスできません

上記の例では、#privateMethodはクラス外部からはアクセスできず、publicMethodを通じてのみ呼び出すことができます。

プライベートメソッドの利点

プライベートメソッドを使用する主な利点は次のとおりです。

内部実装の隠蔽

プライベートメソッドを使用することで、クラスの内部実装を隠蔽できます。これにより、外部からの干渉を防ぎ、クラスのインターフェースをシンプルに保つことができます。

コードの安全性向上

プライベートメソッドはクラス内でのみ使用されるため、誤って外部から呼び出されることがありません。これにより、コードの安全性が向上し、予期しないバグを防止できます。

メンテナンスの容易化

プライベートメソッドを使用することで、クラスの外部に影響を与えることなく、内部のロジックを変更することができます。これにより、コードのメンテナンスが容易になります。

プライベートメソッドを効果的に使用することで、クラスの設計がより安全で効率的になります。次のセクションでは、パブリックメソッドの定義方法とその利点について詳しく説明します。

パブリックメソッドの定義

パブリックメソッドは、クラスの外部からアクセス可能なメソッドであり、クラスのインターフェースとして機能します。パブリックメソッドを使用することで、クラス外部から特定の機能を提供し、クラスの内部データに対する操作を行うことができます。

パブリックメソッドの定義方法

パブリックメソッドは、特別な記号やキーワードを必要とせず、通常のメソッド定義と同じ方法でクラス内に定義します。

class MyClass {
  constructor(name) {
    this.name = name;
  }

  publicMethod() {
    console.log(`Hello, ${this.name}`);
  }
}

const obj = new MyClass("Alice");
obj.publicMethod(); // "Hello, Alice"

上記の例では、publicMethodはパブリックメソッドとして定義されており、クラス外部から直接呼び出すことができます。

パブリックメソッドの利点

パブリックメソッドを使用する主な利点は次のとおりです。

クラスの機能を提供

パブリックメソッドを通じて、クラスの機能を外部に提供します。これにより、クラスが特定のタスクを実行するためのインターフェースを定義できます。

データのカプセル化

パブリックメソッドを使用して、内部データへのアクセスや操作を制御できます。これにより、内部データのカプセル化が実現し、データの整合性を保つことができます。

柔軟なインターフェースの提供

パブリックメソッドを使用することで、クラスの内部実装を変更することなく、外部インターフェースを柔軟に提供できます。これにより、クラスの再利用性と拡張性が向上します。

パブリックメソッドの例

以下は、クラスのパブリックメソッドを使用してオブジェクトの状態を操作する例です。

class Counter {
  constructor() {
    this.count = 0;
  }

  increment() {
    this.count += 1;
  }

  getCount() {
    return this.count;
  }
}

const counter = new Counter();
counter.increment();
console.log(counter.getCount()); // 1

この例では、incrementメソッドとgetCountメソッドがパブリックメソッドとして定義されており、カウンターの値を増加させたり、現在の値を取得したりすることができます。

パブリックメソッドを適切に設計することで、クラスの使用方法が明確になり、コードの可読性と保守性が向上します。次のセクションでは、アクセス指定子の実用例について詳しく説明します。

アクセス指定子の実用例

ここでは、JavaScriptにおけるアクセス指定子の具体的な使用例を紹介します。これにより、アクセス指定子がどのようにクラス設計に役立つかを理解することができます。

アクセス指定子を使ったクラス設計の例

以下は、アクセス指定子を用いた簡単なクラス設計の例です。この例では、プライベートプロパティとメソッド、パブリックプロパティとメソッドを組み合わせています。

class BankAccount {
  #balance;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  #validateAmount(amount) {
    if (amount <= 0) {
      throw new Error("Amount must be positive");
    }
  }

  deposit(amount) {
    this.#validateAmount(amount);
    this.#balance += amount;
    console.log(`Deposited: $${amount}`);
  }

  withdraw(amount) {
    this.#validateAmount(amount);
    if (amount > this.#balance) {
      throw new Error("Insufficient funds");
    }
    this.#balance -= amount;
    console.log(`Withdrew: $${amount}`);
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
account.deposit(500); // Deposited: $500
account.withdraw(200); // Withdrew: $200
console.log(account.getBalance()); // 1300
account.#validateAmount(-100); // エラー: プライベートメソッドにはアクセスできません

この例では、以下のようにアクセス指定子が使用されています:

  • #balance: プライベートプロパティであり、クラス外部から直接アクセスできません。
  • #validateAmount(amount): プライベートメソッドであり、クラス内でのみ使用され、金額の検証を行います。
  • deposit(amount)およびwithdraw(amount): パブリックメソッドであり、外部から呼び出すことができます。これらのメソッドは、プライベートメソッド#validateAmountを使用して金額の検証を行います。
  • getBalance(): パブリックメソッドであり、現在の残高を取得します。

実際のプロジェクトでの応用

アクセス指定子は、実際のプロジェクトにおいて、以下のようなシナリオで役立ちます:

データの隠蔽

重要なデータやロジックをプライベートプロパティやメソッドに隠すことで、外部からの不正な操作を防ぎます。例えば、銀行口座クラスで残高をプライベートプロパティにすることで、直接変更されるのを防ぎます。

内部メソッドの隠蔽

内部でのみ使用される補助的なメソッドをプライベートにすることで、クラスのパブリックインターフェースをシンプルに保ち、外部からの誤用を防ぎます。例えば、データの検証やフォーマット変換を行うメソッドをプライベートにします。

モジュールシステムとの組み合わせ

モジュールシステムと組み合わせて使用することで、さらに強力なカプセル化を実現できます。モジュール内でクラスや関数を定義し、必要なものだけをエクスポートすることで、アクセス範囲を制御します。

アクセス指定子を適切に使用することで、クラスの設計がより堅牢になり、コードの保守性と再利用性が向上します。次のセクションでは、JavaScriptのクラスにおけるアクセス指定子の役割について詳述します。

クラスとアクセス指定子

JavaScriptのクラスにおいて、アクセス指定子は非常に重要な役割を果たします。これにより、クラスの設計がより柔軟で安全になります。以下では、JavaScriptのクラスにおけるアクセス指定子の役割とその具体的な使用方法について説明します。

クラスの基本構造

まずは、JavaScriptのクラスの基本構造を理解するための簡単な例を示します。

class MyClass {
  constructor(value) {
    this.publicValue = value;
    this.#privateValue = value;
  }

  #privateMethod() {
    console.log("This is a private method");
  }

  publicMethod() {
    console.log("This is a public method");
    this.#privateMethod();
  }
}

const obj = new MyClass("example");
obj.publicMethod(); // "This is a public method" "This is a private method"
console.log(obj.publicValue); // "example"
console.log(obj.#privateValue); // エラー: プライベートプロパティにはアクセスできません

この例では、publicValueがパブリックプロパティ、#privateValueがプライベートプロパティとして定義されています。同様に、publicMethodはパブリックメソッド、#privateMethodはプライベートメソッドとして定義されています。

プライベートプロパティとメソッド

プライベートプロパティとメソッドは、クラス内でのみアクセス可能であり、クラスの外部からはアクセスできません。これにより、クラスの内部実装を隠蔽し、外部からの干渉を防ぎます。

プライベートプロパティの使用例

class BankAccount {
  #balance;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
console.log(account.getBalance()); // 1000
console.log(account.#balance); // エラー: プライベートプロパティにはアクセスできません

この例では、#balanceがプライベートプロパティとして定義され、getBalanceメソッドを通じてのみアクセス可能です。

プライベートメソッドの使用例

class BankAccount {
  #balance;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  #validateAmount(amount) {
    if (amount <= 0) {
      throw new Error("Amount must be positive");
    }
  }

  deposit(amount) {
    this.#validateAmount(amount);
    this.#balance += amount;
    console.log(`Deposited: $${amount}`);
  }

  withdraw(amount) {
    this.#validateAmount(amount);
    if (amount > this.#balance) {
      throw new Error("Insufficient funds");
    }
    this.#balance -= amount;
    console.log(`Withdrew: $${amount}`);
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
account.deposit(500); // Deposited: $500
account.withdraw(200); // Withdrew: $200
console.log(account.getBalance()); // 1300
account.#validateAmount(-100); // エラー: プライベートメソッドにはアクセスできません

この例では、#validateAmountがプライベートメソッドとして定義され、depositおよびwithdrawメソッド内でのみ使用されます。

パブリックプロパティとメソッド

パブリックプロパティとメソッドは、クラスの外部からアクセス可能であり、クラスのインターフェースとして機能します。これにより、クラスの機能を外部に提供し、クラスの利用者が特定の操作を実行できるようになります。

パブリックプロパティの使用例

class User {
  constructor(name) {
    this.name = name;
  }
}

const user = new User("Alice");
console.log(user.name); // "Alice"

この例では、nameがパブリックプロパティとして定義され、クラス外部から直接アクセス可能です。

パブリックメソッドの使用例

class User {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, ${this.name}`);
  }
}

const user = new User("Alice");
user.greet(); // "Hello, Alice"

この例では、greetがパブリックメソッドとして定義され、クラス外部から呼び出すことができます。

JavaScriptのクラスにおいて、アクセス指定子を適切に使用することで、クラスの設計がより堅牢で保守性が高くなります。次のセクションでは、モジュールシステムにおけるアクセス指定子の使用方法について詳しく説明します。

モジュールとアクセス指定子

モジュールシステムは、JavaScriptコードを論理的に分割し、再利用性と保守性を向上させるための強力な手段です。モジュールを使用することで、アクセス指定子と組み合わせて、クラスや関数の公開範囲をより細かく制御できます。ここでは、モジュールシステムにおけるアクセス指定子の使用方法とその利点について説明します。

モジュールの基本

JavaScriptのモジュールは、特定の機能をエクスポートし、他のファイルからインポートすることができます。これにより、コードを分割して整理し、必要な部分だけを他のファイルで使用できるようになります。

モジュールのエクスポートとインポート

以下は、モジュールのエクスポートとインポートの基本的な例です。

math.js:

export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

main.js:

import { add, subtract } from './math.js';

console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2

この例では、math.jsで定義された関数addsubtractがエクスポートされ、main.jsでインポートされています。

アクセス指定子とモジュール

モジュールシステムを使用することで、アクセス指定子をさらに強化し、コードのカプセル化を高めることができます。具体的には、プライベートメンバーをモジュール内に隠し、パブリックなAPIだけをエクスポートすることが可能です。

プライベートメンバーを隠す例

以下の例では、モジュール内でプライベートメンバーを使用し、外部には公開しない設計を示します。

bankAccount.js:

const balance = new WeakMap();

class BankAccount {
  constructor(initialBalance) {
    balance.set(this, initialBalance);
  }

  deposit(amount) {
    const currentBalance = balance.get(this);
    balance.set(this, currentBalance + amount);
  }

  withdraw(amount) {
    const currentBalance = balance.get(this);
    if (amount > currentBalance) {
      throw new Error("Insufficient funds");
    }
    balance.set(this, currentBalance - amount);
  }

  getBalance() {
    return balance.get(this);
  }
}

export default BankAccount;

main.js:

import BankAccount from './bankAccount.js';

const account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance()); // 1300

この例では、balanceがモジュール内のプライベートメンバーとして定義されており、外部からは直接アクセスできません。これにより、データのカプセル化が強化されます。

モジュールパターンの利点

モジュールシステムを使用することで、次のような利点があります。

カプセル化の強化

モジュール内でプライベートメンバーを定義し、外部には必要な部分だけをエクスポートすることで、クラスや関数の内部実装を隠蔽できます。

依存関係の明確化

インポートとエクスポートを明確に定義することで、モジュール間の依存関係が明確になります。これにより、コードの理解と保守が容易になります。

再利用性の向上

モジュールごとに機能を分割することで、特定の機能を別のプロジェクトでも再利用しやすくなります。

モジュールシステムとアクセス指定子を組み合わせることで、JavaScriptコードの設計がより堅牢で保守性が高くなります。次のセクションでは、アクセス指定子を効果的に使用するためのベストプラクティスについて紹介します。

アクセス指定子のベストプラクティス

JavaScriptのクラス設計において、アクセス指定子を効果的に使用するためのベストプラクティスを紹介します。これらのベストプラクティスを遵守することで、コードの保守性、再利用性、安全性が向上します。

適切なアクセス指定子の選定

クラスのメンバーに対して適切なアクセス指定子を選ぶことは、コードの明確性と保守性に直結します。以下のガイドラインを参考にしてください。

プライベートメンバー

  • クラスの内部でのみ使用されるデータやメソッドは、プライベートに設定します。
  • 内部ロジックや補助的な処理に使用するメソッドは、プライベートメソッドとして定義します。

パブリックメンバー

  • クラスの外部からアクセスする必要があるメソッドやプロパティは、パブリックに設定します。
  • クラスの機能を外部に提供するためのインターフェースは、パブリックメソッドとして定義します。

カプセル化の徹底

カプセル化は、クラス設計の基本原則であり、データの保護とクラスの内部構造の隠蔽を実現します。カプセル化を徹底することで、クラスの使用方法が明確になり、誤用やバグを防止できます。

内部データの保護

  • クラス内のデータは、必要に応じてプライベートプロパティに設定し、直接アクセスを防ぎます。
  • データへのアクセスや操作は、専用のパブリックメソッドを通じて行います。

インターフェースの明確化

  • クラスの外部から必要な機能のみを提供し、内部実装の詳細を隠蔽します。
  • パブリックメソッドを適切に設計し、クラスの使用方法を明確に示します。

アクセス指定子の組み合わせ

アクセス指定子を組み合わせて使用することで、クラスの柔軟性と安全性を高めます。以下の例を参考にしてください。

class User {
  #password;

  constructor(username, password) {
    this.username = username;
    this.#password = password;
  }

  #encryptPassword(password) {
    return btoa(password); // Base64エンコード
  }

  setPassword(newPassword) {
    this.#password = this.#encryptPassword(newPassword);
  }

  checkPassword(password) {
    return this.#password === this.#encryptPassword(password);
  }

  getUsername() {
    return this.username;
  }
}

const user = new User("Alice", "secret");
console.log(user.getUsername()); // "Alice"
user.setPassword("newSecret");
console.log(user.checkPassword("newSecret")); // true

この例では、#password#encryptPasswordがプライベートメンバーとして定義され、外部からは直接アクセスできません。setPasswordcheckPasswordはパブリックメソッドとして定義され、ユーザーのパスワード管理機能を提供します。

定期的なリファクタリング

コードベースが成長するにつれて、アクセス指定子の使用方法も見直す必要があります。定期的なリファクタリングを行い、以下の点に注意してください。

不要なパブリックメンバーの削減

  • クラスのインターフェースをシンプルに保つために、不要なパブリックメンバーを削除します。

プライベートメンバーの見直し

  • 既存のメンバーが適切なアクセス指定子を持っているかを確認し、必要に応じて修正します。

これらのベストプラクティスを取り入れることで、JavaScriptのクラス設計がより堅牢で保守性の高いものになります。次のセクションでは、アクセス指定子に関連する一般的な問題とその解決方法について説明します。

トラブルシューティング

アクセス指定子を使用する際に遭遇する一般的な問題とその解決方法について説明します。これらの問題を理解し、適切に対処することで、コードの信頼性と保守性を高めることができます。

プライベートメンバーへの不正アクセス

プライベートメンバーに誤ってアクセスしようとすると、エラーが発生します。このエラーは、意図した設計通りにクラスを使用することを強制するためのものです。

問題の例

class MyClass {
  #privateValue = 42;

  getPrivateValue() {
    return this.#privateValue;
  }
}

const obj = new MyClass();
console.log(obj.#privateValue); // エラー: プライベートプロパティにはアクセスできません

解決方法

プライベートメンバーには、クラス内で専用のパブリックメソッドを通じてアクセスするように設計します。

class MyClass {
  #privateValue = 42;

  getPrivateValue() {
    return this.#privateValue;
  }
}

const obj = new MyClass();
console.log(obj.getPrivateValue()); // 42

アクセス指定子の誤用

適切なアクセス指定子を選択しないと、クラスの意図しない部分が外部からアクセス可能になり、バグやセキュリティリスクの原因となります。

問題の例

class MyClass {
  constructor() {
    this._protectedValue = 100;
  }

  _protectedMethod() {
    console.log("This is a protected method");
  }
}

const obj = new MyClass();
console.log(obj._protectedValue); // 100
obj._protectedMethod(); // "This is a protected method"

解決方法

アクセス指定子を適切に使用し、プライベートメンバーとパブリックメンバーを明確に分けます。

class MyClass {
  #privateValue = 100;

  #privateMethod() {
    console.log("This is a private method");
  }

  publicMethod() {
    this.#privateMethod();
    console.log(this.#privateValue);
  }
}

const obj = new MyClass();
obj.publicMethod(); // "This is a private method" 100

クラス間のデータ共有の難しさ

プライベートメンバーはクラス外部からアクセスできないため、異なるクラス間でデータを共有する場合に困難が生じることがあります。

問題の例

class ClassA {
  #privateData = "secret";

  getPrivateData() {
    return this.#privateData;
  }
}

class ClassB {
  useClassA(classA) {
    console.log(classA.#privateData); // エラー: プライベートプロパティにはアクセスできません
  }
}

const a = new ClassA();
const b = new ClassB();
b.useClassA(a);

解決方法

プライベートデータを他のクラスで使用する必要がある場合は、適切なパブリックメソッドやアクセスメソッドを通じてデータを共有します。

class ClassA {
  #privateData = "secret";

  getPrivateData() {
    return this.#privateData;
  }
}

class ClassB {
  useClassA(classA) {
    console.log(classA.getPrivateData()); // "secret"
  }
}

const a = new ClassA();
const b = new ClassB();
b.useClassA(a);

デバッグ時の課題

プライベートメンバーはクラス外部からアクセスできないため、デバッグが難しくなることがあります。

問題の例

デバッグ時にプライベートメンバーの値を確認できない。

解決方法

デバッグ用のメソッドやロギングを導入して、プライベートメンバーの状態を出力します。

class MyClass {
  #privateValue = 42;

  debugPrivateValue() {
    console.log(this.#privateValue);
  }
}

const obj = new MyClass();
obj.debugPrivateValue(); // 42

これらのトラブルシューティング方法を活用することで、アクセス指定子を使用したクラス設計における一般的な問題に対処できます。次のセクションでは、アクセス指定子を使った関数設計の演習問題を提供します。

演習問題

アクセス指定子を使用した関数設計の理解を深めるための演習問題を提供します。これらの問題に取り組むことで、実際にコードを記述しながらアクセス指定子の概念とその応用方法を学ぶことができます。

演習1: シンプルなクラスの設計

以下の仕様を満たすクラスPersonを設計してください。

  • プライベートプロパティ#name#ageを持つ。
  • コンストラクタでnameageを設定する。
  • パブリックメソッドgetNamegetAgeを実装し、それぞれnameageを返す。
  • パブリックメソッドsetNamesetAgeを実装し、nameageを更新する。
// 演習1の解答例
class Person {
  #name;
  #age;

  constructor(name, age) {
    this.#name = name;
    this.#age = age;
  }

  getName() {
    return this.#name;
  }

  getAge() {
    return this.#age;
  }

  setName(name) {
    this.#name = name;
  }

  setAge(age) {
    this.#age = age;
  }
}

const person = new Person("Alice", 30);
console.log(person.getName()); // "Alice"
console.log(person.getAge()); // 30
person.setName("Bob");
person.setAge(25);
console.log(person.getName()); // "Bob"
console.log(person.getAge()); // 25

演習2: バンクアカウントの設計

以下の仕様を満たすクラスBankAccountを設計してください。

  • プライベートプロパティ#balanceを持つ。
  • コンストラクタで初期残高initialBalanceを設定する。
  • パブリックメソッドdepositwithdrawを実装し、それぞれ入金と出金を行う。
  • パブリックメソッドgetBalanceを実装し、現在の残高を返す。
// 演習2の解答例
class BankAccount {
  #balance;

  constructor(initialBalance) {
    this.#balance = initialBalance;
  }

  deposit(amount) {
    if (amount <= 0) {
      throw new Error("Amount must be positive");
    }
    this.#balance += amount;
  }

  withdraw(amount) {
    if (amount <= 0) {
      throw new Error("Amount must be positive");
    }
    if (amount > this.#balance) {
      throw new Error("Insufficient funds");
    }
    this.#balance -= amount;
  }

  getBalance() {
    return this.#balance;
  }
}

const account = new BankAccount(1000);
account.deposit(500);
console.log(account.getBalance()); // 1500
account.withdraw(200);
console.log(account.getBalance()); // 1300

演習3: 複雑なクラス設計

以下の仕様を満たすクラスLibraryBookを設計してください。

  • Bookクラスはプライベートプロパティ#title#authorを持ち、コンストラクタでそれらを設定する。
  • BookクラスにパブリックメソッドgetTitlegetAuthorを実装し、それぞれタイトルと著者を返す。
  • Libraryクラスはプライベートプロパティ#books(配列)を持ち、コンストラクタで初期化する。
  • LibraryクラスにパブリックメソッドaddBookgetBooksを実装し、本を追加し、登録されている本のリストを返す。
// 演習3の解答例
class Book {
  #title;
  #author;

  constructor(title, author) {
    this.#title = title;
    this.#author = author;
  }

  getTitle() {
    return this.#title;
  }

  getAuthor() {
    return this.#author;
  }
}

class Library {
  #books;

  constructor() {
    this.#books = [];
  }

  addBook(book) {
    this.#books.push(book);
  }

  getBooks() {
    return this.#books.map(book => ({
      title: book.getTitle(),
      author: book.getAuthor()
    }));
  }
}

const library = new Library();
const book1 = new Book("1984", "George Orwell");
const book2 = new Book("To Kill a Mockingbird", "Harper Lee");

library.addBook(book1);
library.addBook(book2);

console.log(library.getBooks());
// [{ title: "1984", author: "George Orwell" }, { title: "To Kill a Mockingbird", author: "Harper Lee" }]

これらの演習問題を通じて、アクセス指定子を使用した関数設計の実践的なスキルを身につけてください。次のセクションでは、本記事の内容を総括します。

まとめ

本記事では、JavaScriptにおけるアクセス指定子を使った関数設計について詳しく解説しました。アクセス指定子の基本概念から始まり、JavaScriptで使用できるアクセス指定子の種類、プライベートメソッドとパブリックメソッドの定義方法、実際のコード例、クラス設計における役割、モジュールシステムとの組み合わせ、そしてベストプラクティスやトラブルシューティング方法を取り上げました。

アクセス指定子を適切に使用することで、コードのカプセル化を強化し、保守性と再利用性を高めることができます。また、トラブルシューティング方法や演習問題を通じて、実際の開発で直面する課題に対処するスキルも学びました。

これからのJavaScriptプロジェクトでアクセス指定子を活用し、より安全で効率的なコード設計を実現してください。

コメント

コメントする

目次