06.TS Class

Updated:


TS class

1.What is class ?

  • object 를 만드는 blueprint (설계도)

  • 클래스 이전에 object 를 만드는 기본적인 방법은 function

  • JS 에서도 class 는 ES6 부터 사용 가능

  • OOP 을 위한 초석

  • JS 에서는 클래스도 사용자가 만드는 타입의 하나임

2.class 개요

// class 의 이름의 시작은 보통 대문자로 시작.

class Person {
  name;

  constructor(name: string) {
    this.name = name;
  }
}

const p1 = new Person("Jacob");

console.log(p1);
  • class 키워드를 이용하여 클래스를 만들 수 있습니다.

  • class 이름은 보통 대문자를 이용합니다.

  • new 를 이용하여 class 를 통해 object 를 만들 수 있습니다.

  • constructor 를 이용하여 obejct 를 생성하면서 값을 전달할 수 있습니다.

  • this 를 이용해서 만들어진 object 를 가리킬 수 있습니다.

  • JS 로 컴파일되면 es5 의 경우 function 으로 변경됩니다.

3.constructor & initialize

class Person {
  name: string = "Jacob"; // 직접 Jacob 이라는 string 을 알려줘야 class 에서 initialize 된 것을 알기 때문에 error 가 발생하지 않음
  age!: number; // age 타입의 값을 initialize 해줘야 error 가 생기지 않음
  // class 에서 ! 를 사용하면, 일단은 초기화 하지 않고 나중에 해주겠다는 의미 일종의 pass 근데, 나중에 값을 지정하지 않으면 complie 시 error 발생 (! 쓸때는 주의해서 써야함.)
}

const p1 = new Person();

console.log(p1);

p1.age = 80; // class 에서 ! 사용한것을 지정 해주기 위해 작성된 코드

console.log(p1.age);
  • constructor 를 사용해서 type 지정해주는 경우

class Person {
  name: string = "Jacob";
  age: number;

  constructor(age?: number) {
    if (age === undefined) {
      this.age = 20;
    } else {
    this.age = age;
  }
}

const p1 = new Person(80);
const p2 = new Person()

console.log(p1);

p1.age = 80; // class 에서 ! 사용한것을 지정 해주기 위해 작성된 코드

console.log(p1.age);
  • 생성자 함수가 없으면, 디폴트 생성자가 불립니다

  • 프로그래머가 만든 생성자가 하나라도 있으면, 디폴트 생성자는 사라집니다.

  • strict 모드에서 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 합니다.

  • 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당하지 않는 경우에는 ! 를 붙여서 위험을 표시 합니다.

  • 클래스의 프로퍼티가 정의되어 있지만, 값을 대입하지 않으면 undefined 입니다.

  • 생성자에는 async 를 설정할 수 없습니다.

4.접근 제어자 (Access Modifiers)

class Person { // public 은 전역으로 호출해서 사용할 수 있음
  public name: string = "Jacob";
  private _age!: number; // 공식적이지는 않지만, private 을 사용할때 _ underbar 를 사용해서 호출이 안된다는것을 암묵적으로 표시해서 사용하고 있음

  private constructor(age?: number) { // private 은 constructor 안에서만 호출하는것
    if (age === undefined) {
      this.age = 20;
    } else {
      this.age = age;
    }
  }
  public async init() { }

}

const p1: Person = new Person(80); // private 이기 때문에 Person 을 호출할 수 없음
console.log(p1.);
  • 접근 제어자에는 public, private, protected 가 있습니다.

  • 따로 설정하지 않으면 public 입니다.

  • 클래스 내부의 모든 곳에 (생성자, 프로퍼티, 매서드) 설정이 가능합니다

  • private 으로 설정하면 클래스 외부에서 접근할 수 없습니다.

  • JS 에서는 private 을 지원하지 않아 오랜동안 프로퍼티나 메서드 이름 앞에 _ (underbar) 를 붙여서 사용해왔습니다. (습관인거지, 특별히 기준은 아니다, 즉 안써도 된다는것..)

  • protected 는 private 인데 상속 받으면 접근 할 수 있는 제어자 입니다.

5.initialization in constructor parameters

  • Capter 4 의 코드를 줄여서 다음과 같이 작성 할 수 있습니다.
class Person {
  public constructor(public name: string, private age: number) {}
}

const p1: Person = new Person("Jacob", 80);
console.log(p1);

6.getter & setter

class Person {
  public constructor(private _name: string, private age: number) {}

  get name() {
    // return 을 해줘야함
    // console.log("get");
    return this._name + " Ko";
  }

  set name(n: string) {
    // 뭔가 인자를 받아서 넣어 줘야 하는것
    console.log("set");
    this._name = n;
  }
}

const p1: Person = new Person("Jacob", 80);
console.log(p1.name); // 이와 같이 name 을 꺼내 오는 것을 get, 그것을 하는 함수를 getter

p1.name = "John"; // name 에 뭔가 새로운것을 다시 입력하는 것을 set, 그것을 하는 함수를 setter
console.log(p1.name); // 이와 같이 name 을 꺼내 오는 것을 get, 그것을 하는 함수를 getter

7.readonly properties

class Person {
  public readonly name: string = "Jacob"; // class 밖에서 read 만 할 수 있음
  private readonly country: string;

  public constructor(private _name: string, private age: number) {
    this.country = "Korea";
  }

  hello() {
    this.country = "USA"; // readonly 가 있기 때문에 값을 바꾸려고 할때 error 가 발생됨
  }
}

const p1: Person = new Person("Jacob", 80);

console.log(p1.name); // get

p1.name = "John"; // readonly 를 사용하면 set 을 사용한 값을 변경 할 수 없다

console.log(p1.name);

// readonly 는 초기화 되는 영역에서만 값을 바꿀 수 있으며, 다른 영역에서는 바꿀수 없음
// public 이 있어도 readonly 가 있으면 영역 밖에서 값을 바꿀 수 없음

8.index signatures in class

class Students {
  // 값을 동적으로 처리하기 위해 index signature 를 사용
  [index: string]: "male" | "female";
}

const a = new Students();
a.Jacob = "male";
a.John = "male";
console.log(a);

const b = new Students();
b.Emma = "female";
b.Tom = "male";
b.Sharah = "female";
console.log(b);

// 원래 class 에서 선언을 하면, property 를 항상 initialize 해줬어야 했는데, index signature 는 초기값을 따로 설정 안해줘도 동작함..
// class 에서 index signature 선언한 후, 다른 값을 넣으려면 male, female 에 양식에 맞는 type 으로만 가능하다

9.static properties & methods

class Person {
  public static City = "Seoul";
  public static hello() {
    console.log("안녕하세요", Person.City);
  }
  public static change() {
    Person.City = "Busan";
  }
}

const p1 = new Person();
// p1.hello(); // 기존의 호출 방식 class -> 변수 p1 -> 변수.함수() 메서드 사용

Person.hello(); // static 을 사용하면 변수를 따로 선언 하지 않아도 클래스 명.함수명() 매서드 사용

10.singletons

  • static 을 사용해서 data 를 공유하고, 사용되는 예시로 아래와 같이 singgleton pattern 이 있습니다.
class ClassName {
  private static instance: ClassName | null = null;
  public static getInstance(): ClassName {
    // ClassName 으로 부터 만든 object 가 있으면 그걸 return
    // ClassName 으로 부터 만든 object 가 없으면 , 만든다
    if (ClassName.instance === null) {
      ClassName.instance = new ClassName();
    }
    return ClassName.instance;
  }
  private constructor() {}
}

const a = ClassName.getInstance();
const b = ClassName.getInstance();

console.log(a === b);

11.상속 (inheritance)

  • class 가 다른 class 를 가져다가 자신만의 기능을 추가해서 사용하는 기능 입니다.
class Parent {
  constructor(protected _name: string, private _age: number) {} // protected 는  public 처럼 외부에서는 접근 할 수 없지만, 상속 관계에 있는 상태에서는 접근이 가능함

  public print(): void {
    console.log(`이름은 ${this._name} 이고, 나이는 ${this._age} 입니다.`);
  }

  protected printName(): void {
    console.log(this._name);
  }
}

const p = new Parent("Jacob", 80);

// p._name  // name 은 protected 로 외부에서 아직 사용할 수 없음 -> 상속하게 되면 사용 가능
// p._age // private 이기 때문에 외부에서 사용할 수 없음

p.print(); // 정상적으로 print() 호출됨

// 상속
class Child extends Parent {
  // 기존의 parent 에 있는 값을 over write
  public _name = "John";

  public gender = "male";

  // 만약 child 에서 부모를 받아와서 자신의 생성자를 변경 하는 방법
  constructor(age: number) {
    // 무조건 자식 생성자는 super 를 먼저 호출해줘야 함 (부모를 먼저 호출 한다는 개념임)
    super("Jacob Jr.", age);
    this.printName();
  }
}

const c = new Child(3);

c._name; //기존에는 p._name 은 protected 속성 때문에 출력이 안되지만, 상속자에서 public 으로 over-wirte 했기 때문에 출력 가능

// 결론, 상속을 사용할때, protected, private  를 사용하여 부모, 자식 각자의 영역에서 서로 영향을 미치지 않도록 잘 설정해야 함

11.abstract class

  • abstract 를 통해서 완전하지 않은 class 를 표현 할 수 있으며, 완전하지 않은 class 는 new 를 이용해서 object 를 만들어 낼 수 없습니다.

  • 상속 같은 기능을 통해서 완전한 class 로 만들어서 사용할 수 있습니다.

abstract class AbstractPerson {
  // abstract 를 사용하여면 class 앞에 abstract 라고 써야 됨
  protected _name: string = "Jacob";

  abstract setName(name: string): void;
}

// new AbstractPerson()  // 기능이 완전하지 않다는것을 나타내는 abstract 를 사용했기 때문에 new 를 사용 할 수없음

class Person extends AbstractPerson {
  setName(name: string): void {
    // class 를 사용하기 위해서는 부모인 abstract 를 완전한 형태로 만들어 줘야 함
    this._name = name;
  }
}

const p = new Person();
p.setName();

🔶 🔷 📌 🔑

Reference

Leave a comment