object
를 만드는 blueprint
(청사진, 설계도)JavaScript
에도 es6
부터 class
키워드 사용 가능TypeScript
에서는 클래스도 사용자가 만든 타입의 하나class
키워드를 이용하여 클래스를 만들 수 있다.class
이름은 보통 대문자를 이용한다.new
를 이용하면 class
를 통해 object
를 만들 수 있다.constructor
를 이용하면 object
를 생성하면서 값을 전달할 수 있다. (Java의 class 생성자와 유사)this
를 이용하면 만들어진 object
를 가리킬 수 있다.TS
를 JS
로 컴파일되면 es5
의 경우 function
으로 변경된다.class Person { // class 이름은 대문자로 시작 name; // 생성자 함수 constructor(name: String) { this.name = name; } } // Person obj를 p1에 할당 (새로운 p1 객체를 생성) const p1 = new Person("Mark"); console.log(p1);
default
생성자가 동작한다.constructor
를 이용해 직접 생설자를 정의하면 default
생성자는 사라진다.default
생성자는 매개변수 없이 사용되는 생성자 함수를 의미한다.undefined
이다.async
를 설정할 수 없다.class Person { ame: String = "Mark"; // 직접 할당 => 초기값을 설정해주지 않으면 오류발생! age: Number; // async constructor (x) constructor(age?: Number) { if(age === undefined) { this.age = 20; } else { this.age=age; } } } // 이런 형태 두개 다 지원하려고 한다면 각각의 생성자 생성(오버로딩) // 오버로딩 => 같은 이름, 다른 매개변수 // JS에서는 오버로딩이 안됨. TS에서는 가능. const p1 = new Person(39); const p2 = new Person(); console.log(p1); console.log(p1.age);
클래스 프로퍼티
직접 할당
class Person { name: string = "Kim"; }
strict
모드에서는 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당해야 한다.생성자 함수 사용
class Person { name: string; constructor(name: string){ this.name = name; } }
동적 할당
// 사용 1 class Person { name!: string; // !는 초기값을 class 영역 안이 아닌 밖에서 값을 직접 설정 한다는 의미다. } const p1: Person = new Person(); p1.name // 값을 아직 할당 하지 않았으므로 undefined p1.name = "Lee"; // 동적 할당 // 사용 2 class Person1 { name!: string; // ! 사용 async init(name){ this.name = name; // 비동기로 초기화 } }
- 프로퍼티를 선언하는 곳 또는 생성자에서 값을 할당하지 않는 경우에는
!
를 붙여서 위험을 표현한다.
sync
- 동시에 일어난다는 의미이며 요청과 결과가 동시에 일어납니다. (동기)
async
- 동시에 일어나지 않는다를 의미이며 요청과 결과가 동시에 일어나지 않습니다. (비동기)
public
, private
, protected
가 있다.public
이다.private
으로 설정하면 클래스 외부에서 접근할 수 없다.private
지원하지 않아 오랫동안 프로퍼티나 메서드 이름 앞에 _
를 붙여서 표현했다.class Person { public name: string = "Kim"; private age: 10; } const p: Person = new Person(); console.log(p.name); // Kim console.log(p.age); // 에러 (클래스 외부에서 접근 불가)
생성자함수 매개변수
- 생성자 함수의 매개변수에 접근제어자를 붙여 간편하게 작성 가능
class Person{ public constructor(public name: string, private age: number){} } const p: Person = new Person("Kim",20); console.log(p); // { name: 'Kim', age: 20 } 전체 데이터 조회는 가능 console.log(p.name); // Kim console.log(p.age); // 에러 (직접 접근 불가)
// 접근제어자 public, private class Person { public name: String = "Mark"; // JS에서는 오랫동안 private가 없어서 _age 이런 식으로 이름에 표기를 해둠 // JS에서는 아직도 관행이 남아서 private는 _를 붙여줌. private age: Number; public constructor(age?: Number) { if(age === undefined) { this.age = 20; } else { this.age=age; } } public async init() { } } const p1 = new Person(39); console.log(p1);
- 자바스크립트는
private
를 지원하지 않아 오랬동안 이름 앞에_
를 붙여서 표현했다.
public
: 외부 클래스가 자유롭게 사용할 수 있도록 합니다.
protected
: 같은 패키지 또는 상속관계에 있는 자식 클래스에서 사용할 수 있도록 합니다.
private
: 외부에서 사용될 수 없도록 합니다.
class Person { public constructor(public name: String, public age: Number) { // 파라미터에 public을 붙여줌 } } const p1 = new Person("Mark", 39); console.log(p1); // Person { name: 'Mark', age: 39 }
class Person { public constructor(public name: String, private age: Number) { // age는 외부에서 접근 불가 } } const p1 = new Person("Mark", 39); // p1.age = 24; => 이거 안됨 (private) console.log(p1); // Person { name: 'Mark', age: 39 }
class Person { public constructor(private _name: String, public age: Number) { } get name() { // 접근자 return this._name + "Lee"; } set name(n: String) { // 설정자 this._name=n; } } const p1 = new Person("Mark", 39); console.log(p1.name); // get을 하는 함수: getter p1.name = "Woongjae" // set을 하는 함수: setter console.log(p1.name);
set
은 할 수 없고 get
만 할 수 있는 키워드readonly
: 수정불가능하게 막아 놓을 때 사용. (읽기 전용)class Person { // readonly키워드를 사용하면 프로퍼티 정의 부분애서만 값 초기화 가능 public readonly name: String = "Mark"; private readonly country: String; public constructor(private _name: String, public age: Number) { // readonly키워드를 사용하면 constructor 생성자 안에서만 this로 값 초기화 가능 // 다른 메소드에서는 초기화 불가능! this.country = "Korea"; } hello() { // readonly이므로 수정 불가 // this.country = "China"; } } const p1 = new Person("Mark", 39); console.log(p1.name); // get을 하는 함수 getter // p1.name = "Lee" // set을 하는 함수 setter console.log(p1.name); // get을 하는 함수 getter
- 프로퍼티 값 고정, 프로퍼티 정의 부분과 생성자 함수 안에서만 값 초기화 가능
// class => object를 만들어내는 청사진 // {mark: 'male', jade: 'male'} // {chloe: 'female', alex: 'male', anna: 'female'} class Students { // [index: string]: String; [index: string]: 'male' | 'female'; // string, 항상 male or female로 설정 mark: "male" = "male"; } const a = new Students(); a.mark = "male"; a.jade = "male"; console.log(a); const b = new Students(); b.chloe = "female"; b.alex = "male"; b.anna = "female"; console.log(b);
class Person{ public static CITY = "a"; // Person 클래스만 호출 가능 public city = "a"; // 객체만 호출 가능 public static hello(){} // Person 클래스만 호출 가능 public hi(){} // 객체만 호출 가능 } const p: Person = new Person(); Person.hello() // ok p.hello() // 에러 Person.hi() // 에러 p.hi() // ok
class Person { private static CITY = "Seoul"; public hello() { console.log("hello", Person.CITY); } public change() { Person.CITY = "LA"; } } const p1 = new Person(); p1.hello(); // Seoul const p2 = new Person(); p2.hello(); // Seoul p1.change(); // Person.CITY 값 변경 p2.hello(); // LA
static
프로퍼티는 객체간 공유가 가능하다.
private
로 설정함으로써 new
키워드를 통한 객체 생성 막기class ClassName {
private static instance: ClassName | null = null;
public static getInstance(): ClassName {
// ClassName으로 만든 object가 없으면 생성
if(ClassName.instance === null) {
ClassName.instance = new ClassName(); // 내부에서 생성자 함수 사용 가능 (클래스 안에서 새로운 객체를 생성 후 정적 변수에 할당)
}
// 새로 생성한 object를 리턴
return ClassName.instance;
}
private constructor() { } // private로 외부에서 new를 이용해 생성자 함수 사용 불가능 하도록 막음
}
const a = ClassName.getInstance(); // 처음에는 만들어서 리턴
const b = ClassName.getInstance(); // 두번째 부터는 만들어진 것을 가져와서 리턴
console.log(a === b); // true (같은 object)
class Parent { // protected : 외부에서는 사용 불가하지만 상속하면 사용 가능 constructor(protected _name: String, private _age: Number) { } public prtint(): void { console.log(`이름은 ${this._name} 이고, 나이는 ${this._age} 입니다.`) } protected printName(): void { console.log(this._name, this._age); } } // const p = new Parent("Mark", 39); // p.prtint(); // 이름은 Mark이고, 나이는 39입니다. class Child extends Parent { // 자식 클래스에 생성자가 없으면 부모 클래스의 생성자를 그대로 사용함 // 만약 부모 클래스에 생성자가 없으면 부모 클래스의 default 생성자를 가져온다. public gender = "male"; // 생성자 overide (재정의) constructor(age: number) { // 상속받는 부모 클래스의 생성자를 꼭 호출해야함! (중요!) // 그리고 자식의 생성자에서는 무조건 super 먼저 호출 super("Mark Jr.", age); this.printName(); } } const c = new Child(1); c.prtint(); // Mark Jr. 1 // 이름은 Mark Jr.이고, 나이는 1 입니다.
new
를 통한 객체 생성 불가능abstract
키워드를 붙여줘야 한다.abstract class AbstarctPerson { protected _name: String = "Mark"; // 프로퍼티 선언 가능 abstract setName(name: String): void; // 추상 메소드는 선언부만 작성하고 구현부는 작성하지 않는다. } // new AbstarctPerson(); class Person extends AbstarctPerson { // 추상 메소드 overide (재정의) => 반드시 추상 메소드를 정의해야한다. setName(name: String): void { this._name = name; } } const p = new Person(); p.setName();