【JavaScript】classって何？

# クラスとは
JavaScriptはオブジェクト指向プログラミングができます。

オブジェクト指向プログラミングは、非常に簡単に言うと「**設計図をもとにオブジェクトを作る**」手法です。
設計図には「どんなことができるか」「どんな値を持っているか」なんかを書き、これを**クラス**と呼びます。

オブジェクト指向の詳細は[こちらの記事](https://techplay.jp/column/482)が参考になると思います。

## 用語

- クラス: 設計図のようなもの、オブジェクト指向の要
- インスタンス（オブジェクト）: クラスを実際に使えるよう具現化したもの
- フィールド: クラスで定義できる、値を持っておく場所
- メソッド: クラスでできる動作の実装、関数と似ている

# 例
ここでは、例として本（`Book`）を示すクラスを作ってみます。
本には以下の要素があります。

- タイトル（`title`）: 文字列
- 著者（`authors`）: 文字列が入った配列
    - 著者は複数いる場合もある
- 読み終わったか（`isRead`）: 真偽値
    - あなたがその本を読み終わったか
    - 読み取り専用にするため、`getter`として実装する

また、本には以下の機能を用意します。

- `toJSON`: 本が持っている情報をJSON形式にする
- `read`: 本を読み終わる、ここでは`isRead`を`true`にする

---
では、さっそく実装していきます。

## 新しくクラスを定義する

新しくクラスを定義するには`class`キーワードを使います。
これは`class クラス名 { 実装 }`という形式です。

```js
class Book {
  // ...
}
```

## フィールドを定義する

次に、フィールドを定義します。
ここでは`title`、`authors`、そして`#isRead`が必要です。

フィールドはクラスの`{}`の中に`フィールド名`という形で書けます。
また、`フィールド名 = 初期値`という形で初期値を設定できます。

```js
class Book {
  title
  authors
  #isRead = false // デフォルトでは本は読み終わっていない
}
```

`#isRead`は[プライベートプロパティ](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Classes/Private_properties)という構文を使っています。
これはフィールドを**クラスの外からアクセスできなくする**ものです。

:::note
JavaScriptではフィールドは書かなくても使用できます。
ですが、書いておくことでこのクラスには**どのフィールドがあるかわかりやすくなる**ので、基本は書いておくことをお勧めします。
:::

## コンストラクタを実装する
コンストラクタは、インスタンスの作成時に一度だけ自動で実行される特別なメソッドです。
主にインスタンスの初期化に使われます。

JavaScriptでは`constructor`いう名前のメソッドがコンストラクタになります。
ここでは以下のように実装してみました。

```js
class Book {
  title
  authors
  #isRead = false

  constructor(title, authors) {
    this.title = title
    this.authors = authors
  }
}
```

今回の`Book`クラスのコンストラクタでは、`title`と`authors`を受け取って初期化します。
ここでの初期化は**フィールドに受け取った値をセットする**ことです。

フィールドに値をセットするには、`this`変数を用います。
これは特別な変数で、自身のインスタンスにアクセスするのに使えます。

### インスタンス化してみる
クラスのインスタンスを作るには、`new`演算子が使えます。
これは`new クラス名(コンストラクタの引数)`という形式です。

```js
const book = new Book('本のタイトル', ['著者1'])

// フィールドにアクセス
book.title // '本のタイトル'
book.authors // ['著者1']
```

## `read`メソッドを実装する
`read`メソッドは、呼び出すと`isRead`を`true`に設定します。

```js
class Book {
  title
  authors
  #isRead = false

  constructor(title, authors) {
    this.title = title
    this.authors = authors
  }

  read() {
    this.#isRead = true
  }
}
```

## `toJSON`メソッドを実装する
`toJSON`は以下の情報をJSON文字列に変換して返すメソッドです。

- `title`
- `authors`
- `isRead`

実装には`JSON.stringify`が使えます。

```js
class Book {
  title
  authors
  #isRead = false

  // 略

  toJSON() {
    const obj = { // JSONに変換するオブジェクト
      title: this.title,
      authors: this.authors,
      isRead: this.#isRead
    }
    return JSON.stringify(obj)
  }
}
```

## `isRead`ゲッターを実装する
ゲッターは簡単に言うと、プロパティにアクセスすると呼び出される関数です。

ゲッターとプライベートフィールドを組み合わせることで、**外部から直接変更できないフィールド**を実装できます。

ゲッターは`get 名前() {処理}`という構文で定義できます。

```js
class Book {
  #isRead = false

  // 略
  
  get isRead() {
    return this.#isRead // プライベートフィールドを返す
  }
}
```

### プロパティの場合
もし普通に`isRead`をプロパティとして実装した場合、これは外部から簡単に変更できてしまいます。

```js
const book = new Book('本', ['著者'])
book.isRead // false

// 簡単に変更できる
book.isRead = true
book.isRead // true
```

本来、`isRead`を変更するためには`read`メソッドを呼び出す必要があります。
にも関わらずこのように変更できてしまうのは問題なので、ゲッターとして実装しています。

## 使用例
ここまでで作成した`Book`クラスは、以下のように使用できます。

```js
const book = new Book('読みたい本のタイトル', ['著者1'])

book.title // '読みたい本のタイトル'
book.isRead // false

// isReadに直接代入することはできない
book.isRead = true
book.isRead // falseのまま

book.read()
book.isRead // true

book.toJSON() // { title: '読みたい本のタイトル', author: ... }
```

クラスの詳細や他の機能は[MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/class)をご覧ください。