HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
💌
JJong’s Archive
/
클래스

클래스

Study Date
Nov 13, 2023
Status
Done
Tags
객체 지향 프로그래밍? ⇒ 코드에서 실제와 유사한 객체를 만듦
 
  • 클래스
    • ⇒ 객체의 청사진
      ⇒ 객체가 가지는 프로퍼티나 메서드 등의 구조를 정의
  • 객체(인스턴스)
    • ⇒ 애플리케이션의 로직을 분할해 객체로 각 로직을 관리할 수 있음
      ⇒ 데이터를 저장하고 메서드를 실행하는데 사용하는 자료구조
      ⇒ 하나의 클래스를 기반으로 동일한 구조를 가짐
      ⇒ 1클래스 당 n객체 생성 가능
 
  • JS의 클래스 ⇒ 생성자 함수의 문법 설탕..
    • 속성(like 변수), 생성자, 메서드(like 함수)
    • 속성이나 메서드에 const, let을 써주지 않아도 됨
    • 속성, 메서드에 타입을 각각 써주면 됨
    • 속성의 초기화는 필수가 아님
    • constructor : 생성자 함수, 객체가 생성될 때 사용
    • 메서드는 콜론과 function 키워드를 생략 가능(JS 규칙)
    • class Department { name:string //this.name으로 접근 가능 //기존 object처럼 key, value의 쌍이 아니라 클래스의 필드임 constructor(n: string) { //생성자함수, JS와 TS 모두 지원 this.name = n } getName() { //메서드는 콜론과 function을 생략 가능(원래는 getName: function() {}) return this.name } } const accounting = new Department('Accounting')
    • 클래스의 메서드가 js에서는 prototype안에 메서드로 정의되어 컴파일 된다
    •  
    • es6 미만에는 클래스라는 개념이 없어서 생성자 함수로 컴파일 됨
      • es6에는 클래스가 있긴 하지만 필드가 없다. 따라서 필드 없는 클래스로 컴파일 됨
      •  
    • 특정한 객체의 메서드를 어떤 변수의 값으로 할당하면 해당 메서드를 가리키게 된다.
      • const describe = accounting.describe describe() //호출 가능, 근데 undefined가 나옴(이유는 밑 설명)
    • 메서드(혹은 함수)의 첫번째 매개변수로 this를 넣고 이 this의 타입을 명시해줄 수 있다.
      • 해당 객체만 이 메서드를 호출할 수 있음
      • 함수 호출시 this 매개변수는 안써줘도 된다.
      • 메서드가 아닌 일반 함수(화살표 함수는 안됨)에서 이렇게 명시함으로써 함수 내에 this를 타입을 any가 아닌 특정하게 지정해줄 수 있다
      • class Department { ... getName(this: Department) { //Department 객체만 이 메서드를 호출할 수 있음 return this.name } } const accounting = new Department() accounting.getName() //O, accounting은 Department의 객체이므로 호출 가능 const accountingCopy1 = { getName: accounting.getName } accountingCopy1.getName() //X : getName에서 쓰는 this가 accountingCopy인데, accountingCopy는 name 속성이 없고, // Department의 객체만 getName를 호출할 수 있음 const accountingCopy2 = { name: 'jjong', getName: accounting.getName } //Department 객체임 accountingCopy.getName() //X, Department의 객체만 getName를 호출할 수 있음
        type Department { name: '' } function getName(this: Department) { // Department 타입만 이 함수를 호출 가능 return this.name }
         
  • private, public으로 접근 제어자를 지정할 수 있다
    • public: (기본) 외부에서 접근 가능
    • private: 외부에서 접근 불가능(자식도 불가)
    • +) protected: (for 상속)외부에서 접근 불가능(자식은 가능)
    • 이 접근제어자 개념은 es6에서 생긴 것으로, 그 이전 js에서는 xx
      • 따라서 TS의 js 버전을 es6미만으로 한다면 해당 개념은 컴파일 되지 않고, ts에서 컴파일 오류가 난다고 해도 런타임 오류는 나지 않는다
      class Department { private name:string .. }
    • 생성자 인수에 접근 제어자를 명시해서, 객체 생성 시 받은 인수로 필드를 바로 생성 가능
      • class Department { private isChecked: boolean constructor(private id: number, public: name: string) { isChecked = true //생성자로 선언되는 속성이 아님 } } const accounting = new Department(1, 'accounting') //Department 객체 생성과 동시에 id와 name 필드가 같이 생성됨
      • 여기선 public이라도 명시해줘야 함에 주의
       
  • readonly로 속성을 읽기 전용, 즉 초기화 후에 변화하지 못하게 할 수 있다
    • ts에만 있는 개념
    • class Department { private readonly name:string .. }
 
  • 상속
    • ⇒ 기존에 있던 클래스의 필드-생성자-메서드를 다 받는 것, 여기에 추가도 가능하다
    • 클래스 이름 뒤에 extends 부모클래스 를 덧붙이면 해당 부모 클래스를 상속 한다는 의미
    • 내부 코드가 없다면 걍 Department와 동일한 기능의 클래스가 됨
    • 한 클래스만 상속 가능하다
    • 자식 클래스의 생성자 함수를 따로 만들어 주려면, 생성자 내부에 부모 클래스의 생성자를 무조건 먼저 불러줘야 함
      • 부모 생성자 부르기: super() ⇒ 매개변수도 부모 생성자와 같아야 함
      • 물론 자식 생성자에서도 기존 개념(접근 제어자로 새 변수 선언 등)이 적용된다
      • class Department { ... } class AccountingDepartment extends Department { constructor(id: string, private reports: string[]) { //reports 필드가 생성 super(id, 'Accounting') //부모 생성자 호출, 매개변수 같아야 함 } addReport(text:string) { //자식에서 새로운 메서드 정의 this.reports.push(text) } }
    • 메서드를 오버라이드, 즉 재정의 할 수 있다
      • class Department { ... getName(name: string) { return this.name } } class AccountingDepartment extends Department { constructor(id: string, private reports: string[]) { //reports 필드가 생성 super(id, 'Accounting') //부모 생성자 호출, 매개변수 같아야 함 } getName(name:string) { //부모에 있던 메서드를 오버라이드 if (name === 'Ann') { return } return name } }
      • 추상 클래스
        • 메서드의 오버라이드를 강제하는 것
        • 기본 클래스에서 메서드를 구현x(중괄호 없이 선언), 상속받은 자식 클래스들에서 구현을 미룸
          • 기본 클래스의 메서드는 매개변수와 반환값의 타입은 명시
          • 자식 클래스들에서는 무조건 해당 메서드를 구현해야한다
        • 추상화 하고 싶은 메서드 앞에 abstract를 붙임. 클래스 내에 하나라도 abstract가 있으면 클래스 이름 앞에도 abstract를 붙여야 함 ⇒ 해당 클래스는 추상클래스가 됨
          • 추상 클래스는 상속 받기 위해서만 존재하는 클래스이고, 인스턴스화 할 수 없다
          abstract class Department { abstract describe():string; } class Account extends Department { describe(): string { //필수 return "" } }
       
  • getter, setter
    • 외부에서 필드 값을 얻게하는 get, 외부에서 필드 값을 정의하게 하는 set
    • get 게터이름() { return ~ }
    • set 세터이름(name: string) { ~ }
      • 외부에서 호출: 객체.세터이름 = ‘name’
    • 외부에서 부를 때 메서드가 아닌 속성처럼 접근
      • 객체.게터이름, 객체.세터이름
      • 그래서 외부에선 속성에 바로 접근하는 것 처럼 보임 ㅎ
      class Department { ... get name() { if (!this.name) { throw new Error('No name found') } //로직 추가 가능 return this.name } set name(name: string) { if(!name) {throw new Error ..} this.name = name } } const accounting = new Department('accounting') const departmentName = accounting.name //getter 호출 accounting.name = 'marketing' //setter 호출
 
  • 정적 메서드 & 속성
    • : 인스턴스에선 접근 불가하고, 클래스에서 직접 접근가능하다
    • static을 변수나 메서드 이름 앞에 붙여주면 정적 변수/메서드가 됨
    • 생성자를 포함한 정적 메서드가 아닌 곳에서는 this로 정적 메서드, 속성에 접근할 수 없다
      • 정적 메서드가 아닌 곳에서의 this는 인스턴스를 가리키는 것이기 때문
        • 대신 클래스 명으로는 접근 가능
      • 정적 메서드에서 this는 클래스이다
      class Department { static name: string static createEmployee(employee: string) { return {employee: employee} } } Department.name //o Department.createEmployee //o
 
  • 싱글톤 패턴
    • 클래스당 하나의 인스턴스만 있는 것
    • 생성자를 private으로 막아서 외부에서 인스턴스를 여러개 생성하지 못하도록 함
    • 대신 클래스내에 인스턴스를 미리 선언함. 반환 값은 해당 클래스
    • 그리고 인스턴스를 반환하는 메서드를 public으로 선언해 해당 메서드에서만 인스턴스를 가져오도록 함
      • 해당 인스턴스에서는 지금 클래스에 선언된 인스턴스가 초기화(생성자로 정의됨)가 되었는지 확인
      • 초기화가 안되어 있으면 생성자로 인스턴스를 생성해줌
      • 되어 있으면 기존의 인스턴스를 생성함
      • 인스턴스 반환 메서드는 static으로 선언해서, 외부에서 인스턴스로 접근하지 않고 클래스로 접근하게 한다(어차피 생성자로 인스턴스 생성불가라 인스턴스로 접근 못함)
        • 클래스에 선언된 인스턴스를 여기서 반환할것이라, 해당 인스턴스도 static이어야 한다
      class Department { private static instance: Department; //인스턴스는 static 변수 private constructor(..) { //생성자를 private으로 } static getInstance() { if (this.instance) { //==Department.instance instance이 정의 되었다면 return this.instance } return new Department(..) //정의되어 있지 않으면 생성자로 생성함 } const department = new Department(..) //X const department = getInstance() //O const department2 = getInstance() // department와 같은 인스턴스이다 }