[TS] TypeScript의 Class

2022. 10. 24. 18:51TypeScript

 

Class란 무엇일까?🤔

 

Class는 객체를 생성하는 설계도이다.

Class를 배울 때 많이 사용하는 비유를 예시로 들자면

 

Class: 붕어빵 틀

Class를 사용해 만드는 객체(인스턴스): 붕어빵

붕어빵은 팥붕어빵이 될 수도 있고, 슈크림 붕어빵이 될 수도 있다.

 

즉 Class 를 사용해 객체를 생성할 수 있고, 생성된 객체의 정보는 모두 다르게 설정할 수 있다.

 

 

1. 클래스의 요소

  • 멤버(member) : 클래스의 필드, 메소드, 생성자
  • 필드(field) : 클래스의 상태를 기억
  • 생성자(constructor): 객체가 만들어질 때 초기값을 넣기 위해 호출
  • 메소드(method): 클래스 내의 함수
  • 인스턴스(instance): new연산자에 의해 생성된 객체

말로만 들어선..뭔말인지?! 아래 코드를 통해 자세히 확인가능!

 


2. Class start : 클래스의 기본 틀

//클래스 생성, 클래스 명은 보통 대문자로 시작 
class Person {
	//필드(field)
	name: string; //멤버변수
	age: number; //멤버변수
	
	//생성자
	constructor(name: string, age: number){
		this.name = name;
		this.age = age;
	}
	
	//메소드
	sayHello(){
		console.log(`Hello, my name is ${this.name}`) 
	}
}

//클래스 내에서 멤버를 사용하기 위해 this 키워드 사용

//new 를 사용하여 Person클래스의 인스턴스 생성

let person = new Person('yoii', 25);
console.log(person) // {name: 'yoii' age: 25}
person.sayHello() // Hello, my name is yoii

 

 


2. 접근제어자 : 속성 또는 메소드로의 접근을 제한하기 위해 사용

2-1. public

선언된 멤버를 클래스 외부에서도 자유롭게 접근 가능.

TS의 멤버는 default 로 public으로 선언되지만 명시해도 된다.

class Person {
	public name: string; 
	public age: number; 
	
	constructor(name: string, age: number){
		this.name = name;
		this.age = age;
	}
	
	sayHello(){
		console.log(`Hello, my name is ${this.name}`) 
	}
}

 

2-2. protected

protectd를 사용하면 멤버가 포함된 클래스와 하위클래스를 제외한 외부에서의 접근을 막을 수 있다.

(아래 상속 extends의 설명을 먼저 보고오면 이해가 쉽습니당!)

//기초클래스 (superclass)
class Person {
    protected name: string;

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

    sayHello(name:string){
    	console.log(`Hello, my name is ${name}`) 
    }
}

//기초 클래스 Person에서 extends 키워드로 확장된 클래스
//파생된 하위클래스(subclass)
class Kids extends Person {
    age:number;
    
    constructor(name: string, age: number){
        super(name); 
    	this.age = age;
    }

    sayHello(){
    	console.log(`Hello, my name is ${this.name}, i'm ${this.age}years old`)
    }
} 

let person = new Person('yoii', 25);
console.log(person) // {name: 'yoii' age: 25}
person.name  // Property 'name' is protected and only accessible within class 'Person' and its subclasses.

기초클래스에서  protected로 선언된 name을 클래스 외부에서 접근하면

Property 'name' is protected and only accessible within class 'Person' and its subclasses.

('name' 속성은 보호되며 'Person' 클래스 및 해당 하위 클래스 내에서만 액세스할 수 있습니다.)

와 같은 에러메세지를 만날 수 있다.

 

2-3. private

private로 멤버를 선언하면 class 외부에서 접근하는 것을 막을 수 있다.

private선언된 멤버는 class 내부에서만 사용이 가능하며, 하위클래스 에서도 사용할 수 없다.

//기초클래스 (superclass)
class Person {
    private name: string;

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

    sayHello(name:string){
    	console.log(`Hello, my name is ${name}`) 
    }
}
   
//기초 클래스 Person에서 extends 키워드로 확장된 클래스
//파생된 하위클래스(subclass)
class Kids extends Person {
    age:number;

    constructor(name: string, age: number){
    	super(name);
    	this.age = age;
    }

    sayHello(){
    	console.log(`Hello, my name is ${this.name}, i'm ${this.age}years old`)
    	//ERROR : Property 'name' is private and only accessible within class 'Person'.
    }
}

기초클래스에서  private으로 선언된 name 을 하위클래스에서 사용하면

ERROR : Property 'name' is private and only accessible within class 'Person'. 
('name' 속성은 비공개이며 'Person' 클래스 내에서만 액세스할 수 있습니다.)

와 같은 에러메세지를 확인 할 수 있다.


3. 상속

extends

OPP(객체지향프로그래밍) 에서는 상속을 이용하여 클래스를 확장해 새로운 클래스를 생성할 수 있다.

extends 를 사용하면 상위객체의 멤버를 모두 사용할 수 있다.

 

하위클래스에서  생성자를 정의하기 위해서는  super을 사용하여 기초클래스의 생성자를 호출!

//기초클래스 (superclass)
class Person {
    name: string;

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

    sayHello(name:string){
    	console.log(`Hello, my name is ${name}`) 
    }
}
   
//기초 클래스 Person에서 extends 키워드로 확장된 클래스
//파생된 하위클래스(subclass)
class Kids extends Person {
    age:number;

    constructor(name: string, age: number){
    	super(name); //파생 클래스에서 contructor를 정의하려면 super()를 사용하여 기초클래스의 name 호출!
    	this.age = age;
    }

    sayHello(){
		console.log(`Hello, my name is ${this.name}, i'm ${this.age}years old`)
    }
}

const kid = new Kids();
kid.sayHello('yoii');//Hello, my name is yoii
kid.sayAge(7);//i'm 7years old

Kids 클래스는 Person 클래스를 확장하기 때문에

Person이 가지고 있는 sayHello() 메소드와 , 확장하면서 생성한 sayAge()를 가진 인스턴스를 생성할 수 있다.

 


4. Getters & Setters(캡슐화)

비공개로 설정하려는 속성은 접근제어자의 private로 설정하여 class 속성에 직접 접근하는 것을 막고

속성값을 읽고 수정하는 getter/setter 함수를 사용하여 값을 받아오거나 수정한다.

 

getter/setter 함수를 사용하면 각 객체의 멤버에 접근하는 방법을 세밀하게 제어할 수 있다.

class Person {
	private _name: string;

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

	set name(name:string){
		if(name.length > 10){
			throw new Error('name too long')
		}
		this._name = name;
	}
}

let person = new Person('yoii');
console.log(person.name) // yoii
person.name = 'yoiiyoiiyoiiyoii' // Error : name too long

 

5. readonly

속성을 읽기 전용으로 설정해 값을 변경할 수 없게 만든다.

선언될 때나 생성자에서 값을 설정하면 이후 수정을 할 수 없다. 접근은 가능!

class Person {
	name: string; 
	readonly age: number; 
	
	constructor(name: string, age: number){
		this.name = name;
		this.age = age;
	}
}

let person = new Person('yoii', 25); // 선언 시 값 설정
console.log(person); // {name: 'yoii', age:25}
person.name = 'dong';
console.log(person); //{name:'dong', age:25}
person.age = 23; // Cannot assign to 'age' because it is a read-only property.

Person클래스의 인스턴스를 생성할 때 값을 설정하여 이후 person.age 를 통해 값을 수정하려면

Cannot assign to 'age' because it is a read-only property. (읽기 전용 속성이므로 '연령'에 할당할 수 없습니다.)

와 같은 에러메세지를 만날 수 있다.

 

인스턴스를 생성할 때 값을 지정해주지 않고  class 에서 값을 설정하는 방법도 있다.

class Person {
	name: string; 
	readonly age: number; 
	
	constructor(name: string, age: number){
		this.name = name;
		this.age = age = 10; // 생성자에서 값 설정
	}
}

let person = new Person('yoii', 25); 
console.log(person); // {name: 'yoii', age:20} // 생성자에서 설정한 값으로 출력

위와 같이 클래스에서 값을 지정하면 인스턴스를 생성하며 값을 할당해도 출력시 클래스에서 지정한 값으로 출력된다.

 


6. static

클래스 내부의 인자나 함수는 new 생성자를 통해 인스턴스를 생성 후 사용할 수 있다.

 

그러나 static을 사용하면 인스턴스를 생성하지 않고 class 내부의 인자나 함수를 사용할 수 있다.

“.클래스명”을 앞에 붙여 static 멤버에 접근할 수 있다.

 

class Add {
	add(x:number, y:number){
		console.log( x + y );
    }
}

let addCal = new Add();
addCal.add(2,5); //7

위와 같이  addCal 인스턴스를 생성하여 Add 클래스 내부의 함수를 사용할 수 있다. 

static을 사용한다면 인스턴스를 생성하지 않는 아래코드로 사용가능하다. 🔻

class Add {
	static add(x:number, y:number){
		console.log( x + y );
    }
}

Add.add(2,5) // 7

 


7. 추상클래스(abstract)

추상클래스는 다른 클래스가 파생될 수 있는 기초클래스이며 직접 인스턴스를 생성할 수 없다.

즉, 추상클래스는 사용을 위해서는 상속을 강제하는 클래스이다.

class 앞에 abstract 키워드를 사용해 추상클래스나 추상 메소드를 정의한다.

추상클래스에 구현되어있지 않은 메소드를 하위클래스에서 필수로 구현해주어야 한다.

//기초클래스 (superclass)
abstract class Person {
    name: string;

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

    abstract sayHello():void
}
   
//기초 클래스 Person에서 extends 키워드로 확장된 클래스
//파생된 하위클래스(subclass)
class Kids extends Person {
    constructor(name: string){
    	super(name)
    }

    //파생된 클래스에서 구현 필수
    sayHello(): void{ 
    	console.log(`Hello, my name is ${this.name}`)	 
    }
}

const person = new Person('yoii')
//Error : Cannot create an instance of an abstract class.

const kid = new Kids('yoii');
kid.sayHello();//Hello, my name is yoii

추상클래스 Person 에서 sayHello()는 구현되어있지 않다.

Person을 확장한 하위클래스 Kids에서 구현되어있지 않은 sayHello()를 필수로 구현해야만 한다. 

 

또한 추상클래스는 인스턴스를 생성할 수없으므로 , new Person() 으로 인스턴스를 생성한다면

Cannot create an instance of an abstract class.(추상 클래스의 인스턴스를 만들 수 없습니다.)

와 같은 에러메세지를 만날 수 있다.