9.1 基本的な概念
カプセル化は、オブジェクト指向プログラミング(OOP)のキーコンセプトの一つで、オブジェクトの内側の実装詳細を隠し、厳密に定義されたインターフェースを通じてそれらの詳細にアクセスできるようにするものだよ。これによってセキュリティが向上し、コード管理も簡単になるんだ。
カプセル化の利点:
- データの隠蔽: カプセル化は内側の実装詳細を隠して、必要なメソッドやプロパティだけにアクセスを提供することができるんだ。これにより、オブジェクトの誤った使用を防ぎ、コードの安全性を向上させるよ。
- アクセス制御: カプセル化により、データやメソッドへのアクセスを制御し、定義されたメソッドを通じてだけオブジェクトの内部状態を変更できるようにすることができるよ。
- メンテナンス性: カプセル化はコードのメンテナンスを向上させるんだ。実装に変更を加えても、クラスの外部インターフェースには影響を与えないからね。これにより、クラスを使用しているコードを変更することなく、実装を改善できるんだ。
- テストの向上: カプセル化はオブジェクトの内部実装を分離することで、モジュールテストを簡単にし、予期しない副作用の発生を減らすことができるんだ。
JavaScriptでは、カプセル化はメソッドとプロパティを使用して実現されるよ。ES2022からは、プライベートフィールドやメソッドも利用できるようになったんだ。
9.2 クロージャによるカプセル化
ES2022のプライベートフィールドの導入前は、JavaScriptでのカプセル化はよくクロージャを使って達成されていたんだ。
例:
- 変数
countは関数createCounterの内部でのみアクセス可能で、外部からはアクセスできないんだ。 - メソッド
increment、decrement、getCountはプライベート変数countとやりとりできるんだ。
JavaScript
function createCounter() {
let count = 0; // プライベート変数
return {
increment() {
count++;
console.log(count);
},
decrement() {
count--;
console.log(count);
},
getCount() {
return count;
}
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
console.log(counter.getCount()); // 2
counter.decrement(); // 1
9.3 ES2022のプライベートフィールド
ES2022では、#シンボルを使用してプライベートフィールドやメソッドを宣言できるようになったんだ。プライベートフィールドやメソッドはクラスの外部からアクセスしたり変更することはできないよ。
例:
- プライベートフィールド
#nameと#ageは#シンボルを使って宣言されているんだ。 - メソッド
getName、getAge、setName、setAgeはプライベートフィールドとやりとりできるんだ。 - クラスの外部からプライベートフィールドにアクセスしようとするとエラーになるよ。
JavaScript
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) {
if (age > 0) {
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
console.log(person.#name); // エラー: プライベートフィールドにはアクセスできない
9.4 プライベートメソッド
プライベートメソッドも#シンボルを使って宣言できて、クラスの外からアクセスすることはできないんだ。
例:
- プライベートフィールド
#balanceとプライベートメソッド#logTransactionはオブジェクトBankAccountの状態を管理するために使われているよ。 - プライベートメソッド
#logTransactionは、depositやwithdrawといった公開メソッド内で呼ばれて、トランザクションを記録するんだ。
JavaScript
class BankAccount {
#balance;
constructor(initialBalance) {
this.#balance = initialBalance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
this.#logTransaction('deposit', amount);
}
}
withdraw(amount) {
if (amount > 0 && amount <= this.#balance) {
this.#balance -= amount;
this.#logTransaction('withdraw', amount);
}
}
getBalance() {
return this.#balance;
}
#logTransaction(type, amount) {
console.log(`Transaction: ${type} ${amount}`);
}
}
const account = new BankAccount(1000);
account.deposit(500); // "Transaction: deposit 500"
console.log(account.getBalance()); // 1500
account.withdraw(200); // "Transaction: withdraw 200"
console.log(account.getBalance()); // 1300
account.#logTransaction('test', 100); // エラー: プライベートメソッドにはアクセスできない
GO TO FULL VERSION