2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【TypeScript | JavaScript】Classまとめ

Last updated at Posted at 2023-03-11

はじめに

最近ちゃんとTypeScriptについて勉強し直しまして、
Classを今までちゃんと使ってこなかったなあと思い、記事にしました。

同じような方の参考になれば幸いです。
Classの説明をする前にオブジェクト指向について理解しておく必要があるので、簡単に説明します。

オブジェクト指向とは

話題のBingAIにお願いしました

オブジェクト指向とは、プログラミングの考え方の一つで、現実世界に存在するものを「オブジェクト」として扱い、その特徴や機能を定義することです。オブジェクト指向には、以下のようなメリットがあります。

  • オブジェクトを再利用しやすくすることで、開発効率や保守性を高めることができます。
  • オブジェクト同士の関係を明確にすることで、設計や理解がしやすくなります。
  • オブジェクトの内部構造や動作を隠蔽することで、安全性や信頼性を向上させることができます。

わかりやすいですね。ここで具体例も紹介しておきます。

具体例

とある商品を題材に考えてみます。

その商品には以下のプロパティ(特徴・性質)があるとします。

  1. String型の名前
  2. number型の価格
  3. 名前を変更することができる。
  4. 商品をカートに入れることができる。

この場合、TypeScriptでは以下のようにオブジェクトを定義することができます。

const goods_A = {
  name: 'A商品',          // 名前
  price: 100,            // 価格
  rename(n: string): void {    // 名前変更
    this.name = n;
  },
  addToCart(): void {          // カートに入れる
    cart.push(this.name)
  }
}

goods_A.name
// 'A商品'

goods_A.rename('a商品')
goods_A.name
// 'a商品'

このようにオブジェクトとして定義し、そのプロパティに「名前」や「価格」や、
「名前変更」や「カートに入れる」といった機能を定義していくプログラミング手法をオブジェクト指向と言います

1. classについて

先ほどの例から考えてみます。

以下のように商品Aがあります。

typescript
const goods_A = {
  name: 'A商品',
  price: 100,
  rename(n: string): void {
    this.name = n;
  },
  addToCart(): void {
    cart.push(this.name)
  }
}

商品が複数件ある場合、

typescript
const goods_B = {
  name: 'B商品',
  price: 100,
  rename(n: string): void {
    this.name = n;
  },
  addToCart(): void {
    cart.push(this.name)
  }
}

const goods_C = {



全ての商品で同じ動きをさせるためには作成分のオブジェクトを定義する必要が出てきますが、
こんなことはしてられません。

オブジェクトの設計書みたいなものがあれば、それを元に増やすことができそうです。
そのオブジェクトの設計書がClassです

先ほどの商品の設計書をClassを使い定義し、商品のオブジェクトを生成します。

ちなみに、クラスから作成したオブジェクトをインスタンスと言います。

クラスからオブジェクト生成し、解読していきます。

typescript
// クラス定義
class Goods {
  name: string;
  price: number;

  constructor(n: string, p: number) {
    this.name = n;
    this.price = p;
  };

  rename(n: string): void {
    this.name = n
  };

  addToCart(): void {
    cart.push(this.name)
  };
}

// インスタンス生成
const goods_A = new Goods('商品A', 100)
goods_A.name
// 'A商品'

2. constructor関数とは

constructor関数とは、クラスで作成されたオブジェクトの初期化のためのメソッドです。
constructor関数は、クラスが呼び出された際に最初に実行されます。

つまり、new Hoge()の際に実行されるメソッドです。

class
  name: string;
  price: number;

  constructor(n: string, p: number) {
    this.name = n;
    this.price = p;
  };

先ほど作成したクラスを見ると、
namestring型で定義、
pricenumberで定義し、
constructor関数で引数で受け取った値を初期値として格納しています。

new Goods('商品A', 100)

このようにオブジェクトを生成します。
試しに引数に渡している値を変更し、namenumber型をを入れてみます。

スクリーンショット 2023-03-10 21.17.03.png

このようにエラーになります。
constructor関数の引数の型定義(n: string, p: number)が、
インスタンス化する時に作用していることが確認できますね。

3. 【TypeScriptのみ】 アクセス修飾子

TypeScriptでは、プロパティのアクセシビリティを制御するため、クラスのプロパティに対してアクセス修飾子public private protectedを使うことができます。

typescript
class Goods {
  owner: string; // 自動的にpublicになります。
  private name: string;
  public price: number;
  protected id: number;
}
  • public
    • デフォルトはこれ。何も記載がないとpublicになります。
    • どこからでもアクセスできる
  • private
    • 同じクラス内からのみアクセスできる
  • protected
    • 同じクラスとサブクラス内からのみアクセスできる

なぜ必要なのか

不用意に値を変更できないようにするためです。

次の例で説明します。

typescript
class Goods {
  public name: string;

  constructor(n: string) {
    if (n.length < 100) {
      this.name = n;
    } else {
      this.name = '100文字以上'
    }
  };

  rename(n: string): void {
    if (n.length < 100) {
      this.name = n
    }
  };
}

このように100文字以下のバリデーションがついたnameプロパティがあったとします。

アクセス修飾子がpublicの場合

publicのプロパティはどこからでもアクセスできるため、
以下のように、renameメソッドを通しても通さなくても値を変更できてしまいます。

typescript
const goods_A = new Goods('商品A')

// 1. renameメソッドを通す
goods_A.rename('hoge')

// 2. 直接値を変更
goods_A.name = 'fuga'

renameメソッド内では100文字のバリデーションがかかるのに対し、
直接変更する場合はバリデーションをかけることができません。

アクセス修飾子がprivateの場合

privateのプロパティは同じクラス内からのみアクセスできるため
以下のように直接指定はできません

スクリーンショット 2023-03-11 23.50.22.png

この例で不用意に値を変更しないようにアクセスプロパティを適切につける意味が理解できたと思います。

4. 【TypeScriptのみ】 constructor関数の省略記法

さて、次のコードを見て何を思いますか?

typescript
class Goods {
  name: string;
  private price: number;
  private store: string;
  type: string;

  constructor(n: string, p: number, s: string, t: string) {
    this.name = n;
    this.price = p;
    this.store = s;
    this.type = t;
  };
}

私であれば冗長だなぁ...と思います。
TypeScriptであればこの冗長を解決できます。
それがこちらです

typescript
class Goods {
  constructor(
    public name: string,
    private price: number,
    private store: string,
    public type: string
  ){};
}

このように初期化処理をかなりシンプルに記述できます。

constructor関数の引数にアクセス修飾子とプロパティ名を書くだけで自動で初期化処理まで行ってくれます。

アクセス修飾子は必ずつける必要があります。
publicであっても省略することはできません。

ちなみにこのコードをJavaScriptにコンパイルするとこうなります。

javascript
class Goods {
  constructor(n, p, s, t) {
    this.name = n;
    this.price = p;
    this.store = s;
    this.type = t;
  };
}

アクセス修飾子がなくなり、全てconstructor関数でthisの中に格納する形になっていますね。

5. まとめ

  1. オブジェクト指向とは、現実世界に存在するものを「オブジェクト」として扱い、その特徴や機能を定義すること。
  2. classとは、オブジェクトの設計図のようなもの。
  3. constructor関数とは、クラスで作成されたオブジェクトの初期化のためのメソッド。
  4. TypeScriptでは、不用意に値を変更できないようにするため、クラスのプロパティに対してアクセス修飾子public private protectedを使い、アクセスの制限をかけることができる。
  5. TypeScriptでは、初期化処理を簡潔にかける省略記法が存在する

他にもinterfaceを使ってclassを実装する方法だったり、継承だったり、説明できることはたくさんありますが、今回はここまでの基本的な使い方までとさせていただきます。

続きについてはまた今度書きたいと思います。

2
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?