JavaScript getterとsetterに関するまとめ📔

## はじめに

JavaScript の `getter` と `setter` についてメモ🤗

## 目次

1. [まずはざっくり説明](#-まずはざっくり説明)
2. [getterとsetterを使う場合](#-getterとsetterを使う場合)
3. [getter・setterのメリット](#-gettersetterのメリット)
4. [クラスでのgetter・setter](#-クラスでのgettersetter)
5. [実務での使い所](#-実務での使い所)
5. [まとめ](#-まとめ)
6. [参考文献](#-参考文献)

## 🧷 まずはざっくり説明
👉 `getter`：値を「取得」するための関数
👉 `setter`：値を「設定」するための関数

これらは **オブジェクトのプロパティを関数経由で操作できる** ようにする仕組み！
使うときは普通のプロパティのように書けるのが特徴。

### ✅ まずは普通のプロパティ操作
たとえば、オブジェクトに名前と年齢があるとする。
```typescript
const person = {
  name: "Alice",
  age: 25
};

console.log(person.name);    // → Alice
person.age = 30;             // 値を変更
console.log(person.age);     // → 30
```
↑ 普通はこんな感じで `.` を使ってプロパティにアクセスする。

## 🧷 getterとsetterを使う場合
次に、このオブジェクトに `getter` と `setter` を追加する！
```typescript
const person = {
  firstName: "Alice",
  lastName: "Johnson",
  
  // getter: 値を取得する
  get fullName() {
    return `${this.firstName} ${this.lastName}`;
  },

  // setter: 値を設定する
  set fullName(name) {
    const parts = name.split(" ");
    this.firstName = parts[0];
    this.lastName = parts[1];
  }
};

console.log(person.fullName);     // → "Alice Johnson"（関数っぽく書かなくてOK！）

person.fullName = "Bob Brown";    // setterで値を更新
console.log(person.firstName);    // → "Bob"
console.log(person.lastName);     // → "Brown"
```
#### 💡 ポイント解説
* `get` で関数を定義 👉 値を取得するときに自動で呼び出される
* `set` で関数を定義 👉 値を代入するときに自動で呼び出される

**関数呼び出しっぽくせずに、普通のプロパティのように扱えるのが特徴！**

## 🧷 getter・setterのメリット
#### 1. プロパティを読みやすく・書きやすくできる！
```typescript
console.log(person.fullName);  // 関数呼び出し不要でスッキリ
```

#### 2. データの整形やチェックができる！
例えば、年齢をセットする時に「マイナスはダメ！」というチェックができる
```typescript
const user = {
  _age: 0,    // 内部的に使う変数（外からは見せない）
  
  get age() {
    return this._age;
  },
  
  set age(value) {
    if (value >= 0) {
      this._age = value;
    } else {
      console.log("年齢は0以上である必要があります！");
    }
  }
};

user.age = 30;          // → OK
console.log(user.age);   // → 30

user.age = -5;           // → "年齢は0以上である必要があります！"
console.log(user.age);   // → 30（変更されない）
```

## 🧷 クラスでのgetter・setter
オブジェクトだけじゃなくて、クラスでも使える！
```typescript
class Rectangle {
  constructor(width, height) {
    this.width = width;
    this.height = height;
  }

  // 面積を取得する getter
  get area() {
    return this.width * this.height;
  }

  // 幅と高さを同時に設定する setter
  set dimensions({ width, height }) {
    this.width = width;
    this.height = height;
  }
}

const rect = new Rectangle(10, 5);
console.log(rect.area);        // → 50

rect.dimensions = { width: 7, height: 3 };
console.log(rect.area);        // → 21
```

## 🧷 実務での使い所
### ① データの整形・加工
データを扱うときに、表示用と内部データを分ける場面で便利！

#### 例：金額を表示する時に「,」区切りで整形
```typescript
const product = {
  _price: 1000,

  get price() {
    // カンマ区切りに整形
    return `${this._price.toLocaleString()} 円`;
  },

  set price(value) {
    if (value >= 0) {
      this._price = value;
    } else {
      console.error("金額は0以上にしてください");
    }
  }
};

console.log(product.price);    // → "1,000 円"

product.price = 200000;        // 新しい金額をセット
console.log(product.price);    // → "200,000 円"

product.price = -100;          // → "金額は0以上にしてください"
```
* 内部的には数値だけど、外に見せるときは 見やすいフォーマットで表示！
* 不正なデータは `setter` でチェック！

### ② バリデーションやデータ保護
直接プロパティにアクセスさせたくないときに使う！

#### 例：パスワードを直接表示できないようにする

↓ だと`user._password`へアクセスできてしまうので...
```typescript
const user = {
  _password: "superSecret123",

  get password() {
    return "****";  // 外部には表示させない
  },

  set password(value) {
    if (value.length >= 8) {
      this._password = value;
    } else {
      console.error("パスワードは8文字以上にしてください");
    }
  }
};

console.log(user.password);     // → "****"（外部には隠す）
console.log(user._password);    // → superSecret123

user.password = "newPass456";   // OK
console.log(user.password);     // → "****"
console.log(user._password);    // → newPass456

user.password = "123";          // → "パスワードは8文字以上にしてください"
```

↓ [クロージャ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Closures)を使って外部から見えない様にする。
```typescript
const user = (function() {
  let _password = "superSecret123";

  return {
    get password() {
      return "****";  // 外部には表示させない
    },

    set password(value) {
      if (value.length >= 8) {
        _password = value;
      } else {
        console.error("パスワードは8文字以上にしてください");
      }
    }
  };
})();

console.log(user.password);     // → "****"（外部には隠す）
console.log(user._password);    // → undefined

user.password = "newPass456";   // OK
console.log(user.password);     // → "****"
console.log(user._password);    // → undefined

user.password = "123";          // → "パスワードは8文字以上にしてください"
```
* `getter` で隠す 👉 セキュリティ強化！
* `setter` でチェック 👉 不正なデータを防止！

### ③ 計算プロパティ
オブジェクト内で計算した値を返したいときに便利！

#### 例：カートの合計金額を計算
```typescript
const cart = {
  items: [
    { name: "リンゴ", price: 150, quantity: 2 },
    { name: "バナナ", price: 100, quantity: 3 }
  ],

  // 合計金額を計算するgetter
  get total() {
    return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0);
  }
};

console.log(cart.total);    // → 150*2 + 100*3 = 600
```
* `get` を使うことで、毎回計算を自動でしてくれる
* 外からは `cart.total` でアクセスするだけ！関数っぽく見えないからスッキリ！

### ④ クラスのカプセル化
クラスで使うと、内部データの保護や計算を自動化できる！

#### 例：BMI計算クラス
```typescript
class Person {
  constructor(height, weight) {
    this.height = height;   // 身長 (m)
    this.weight = weight;   // 体重 (kg)
  }

  // BMI計算
  get bmi() {
    return (this.weight / (this.height ** 2)).toFixed(2);
  }

  set bmi(value) {
    console.log("BMIは自動計算なので変更できません！");
  }
}

const p = new Person(1.75, 68);
console.log(p.bmi);         // → "22.20"（計算結果を取得）

p.bmi = 30;                 // → "BMIは自動計算なので変更できません！"
console.log(p.bmi);         // → "22.20"（変更されない）
```
* `get` で計算は自動でやってくれる！
* `set` で変更を防止できる 👉 BMIは勝手に計算されるから直接書き換えさせない！

🚀 でも使わない場面も多い！
実務では普通のプロパティ操作だけで十分なことが多いから、`getter` ・ `setter` は使いすぎると逆にコードが複雑になることもある。

## 🎉 まとめ
* `getter`：値を取得する時に関数呼び出しを自動で行う
* `setter`：値を代入する時に関数呼び出しを自動で行う
* 普通のプロパティみたいに書けてスッキリ！
* データのチェックや整形に便利！
* `getter`・`setter`の使いどころの見極めポイント
    * データを加工して表示したい 👉 `getter` が便利！
    * 値のバリデーションやチェック 👉 `setter` が有効！
    * 計算結果を毎回出したい 👉 `getter` で自動計算！
    * セキュリティ対策やカプセル化 👉 `getter` で隠す！

## 💫 参考文献
* [ゲッター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/get)
* [セッター](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/set)
* [クロージャ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Closures)