홍열 2022. 2. 20. 13:27
728x90

01. what are classes

object를 만드는 설계도

클래스 이전에 object를 방법은 function 

javascript es6에서부터 class 키워드 사용가능 (접근제어자 부족...)

typescript에서는 클래스도 사용자가 만드는 타입중에 하나

02. Quick Start - class

기본 형태

class Person {}   

const p1 = new Person();
console.log(p1)

tsconfig.json에서 target을 es5로 넣고, 컴파일해보면 class가 function으로 구현되어 있는걸 볼 수 있다. 

"use strict";
var Person = /** @class */ (function () {
    function Person() {
    }
    return Person;
}());
var p1 = new Person();
console.log(p1);

object가 만들어졌을 떄, 프로퍼티를 가지게 만들자.(consturctor 이용)

this를 사용하면 만들어진 object를 가르킬 수 있다.

class Person {
    name:string; 
    constructor(name:string) {
        this.name = name;
    }
}   
const p1 = new Person("Hong");
console.log(p1)

03. constructor & initialize

class Person {
    name:string; 
    age:number;
}   
const p1 = new Person();

Person class의 입장에서는 name과 age가 초기화된적이 없기때문에 에러가 난다.
각 변수에 값을 직접 넣어주거나, 초기화가 필요...

p1을 생성후에 나중에 값을 넣어줄때도 클래스 자체는 모른다. 

하지만 이걸 의도적으로 표시해줄수 있는게 ! 이다.  ! 를 쓸때는 주의해야된다. 

class Person {
    name:string = "Mark"; 
    age!:number;
}   
const p1 = new Person();
console.log(p1)
p1.age = 39
console.log(p1.age);

default 생성자도 있다. 별도의 생성자가 없으면 실행된다. 

프로그래머가 construtor를 구현한다면,default생성자는 실행되지 않는다.

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

    constructor(age:number) {
        this.age = age
    }
}   
const p1 = new Person(29);
console.log(p1)
console.log(p1.age);

async를 지원하지 않는다. 

04. 접근제어자(Access Modifiers)

기본적으로 모두 외부 접근 가능하다. (public)

class Person {
    public name:string; 
    public age:number;

    constructor(name:string, age:number) {
        this.name = name;
        this.age = age
    }
}   
const p1 = new Person("hong", 37);

private - 외부에서 접근 불가

class Person {
    public name:string; 
    private age:number;

    constructor(name:string, age:number) {
        this.name = name;
        this.age = age
    }
}   
const p1 = new Person("hong", 37);
// p1.age <---호출 안된다.

protected - 상속간에만 허용

05. initialization in constructor parameters

생성자의 파라미터에서 바로 초기화 하는 방법

constructor의 파라미터에 public을 붙이면 된다. (private, protected도 가능)

class Person {
    // name:string; 
    // age:number;

    constructor(public name:string, public age:number) {
        // this.name = name;
        // this.age = age;
    }
}   
const p1 = new Person("hong", 37);
p1.name
p1.age

06. Getters & Setters

이걸 이용해서 정보 조작을 막자

class Person {
    constructor(private _name:string, private age:number) {}
    get name() {
        return this._name
    }
    set name(name:string) {
        this._name = name
    }
}   
const p1 = new Person("hong", 37);

//프로퍼티처럼 실행
console.log(p1.name)

p1.name = "yeol"
console.log(p1.name)

07. readonly properties

readonly 키워드를 넣어서 읽기 전용 속성으로 만들자. 

변경시에 에러를 보여준다. 

프로퍼티 초기화에서는 가능(선언과 동시에 할당 , consturctor)

class Person {
    public readonly name:string = 'Hong';
    private readonly country:string = 'korea';
    constructor(public _name:string, public age:number) {}

    hello() {
        //error - readonly
        this.country = 'qwe'
    }
}   
const p1 = new Person("hong", 37);

//error - readonly
p1.name = 'yeol'

08. Index Signatures in class

동적으로 프로퍼티 이름이 바뀔 때, 고려해볼만한 기능

// class => object를 만들어내는 행위
// A반과 B반을 모두 나타낼 수 있는 객체
// {mark:'male', jade:'male'}
// {jenny:'female', alex:'male', anna:'female'}

class Students {
    //mark:string = 'male' 
    //위에처럼 하면 동적으로 처리 불가 
    
    //index signatures 이용해서 동적 처리를 지원하자
    //프로퍼티의 이름은 모르지만, 그게 가진 값은 string
    [index:string]:string;

    //좀 더 정확하게 하려면 "male", "female"만 가질수 있도록 union을 하면된다. 
    //프로퍼티의 이름은 모르지만, 그게 가진 값은 male 혹은 female
    //[index:string]:"male"|"female";
}
const classA = new Students();
classA.mark = "male";
classA.jade = "male";

console.log(classA);

const classB = new Students();
classB.jenny = "female";
classB.anna = "female";
classB.alex = "male";

console.log(classB)

09. Static Properties & Methods

클래스간 공유이기때문에 한쪽에서 바뀌면 다른쪽도 영향을 받는다.

 

class Person {
    public static CITY = "seoul";
    public static hello() {
        console.log('hello')
    }
    public change() {
        Person.CITY = "suwon";
    }
}

const p1 = new Person();
//static로 선언시 p1.CITY, p1.hello()로 사용할 수 없다.

//Person.hello() 이렇게 사용할 수 있다. 
Person.hello();
console.log(Person.CITY); //seoul

p1.change();
console.log(Person.CITY); //suwon

10. Singletons

싱클톤이란..단 하나의 오브젝트만 가지고 논다.

class ClassNameA {}


const a = new ClassNameA()
const b = new ClassNameA()

//a와 b는 각각 다른 객체
//어디서든지 생성할 수 없게 막아아한다. private constructor이용
class ClassNameB {
    //instance는 ClassNameB or null을 가질 수 있으므로.. 
    private static instance:ClassNameB | null = null;
    
    public static getInstance() : ClassNameB {

        if (ClassNameB.instance === null) {
            ClassNameB.instance = new ClassNameB()
        }
        return ClassNameB.instance;
        
        //classNameB으로부터 만든 objecr가 있으면 그걸 리턴
        //없으면 새로 만들어서 리턴
    }
    private constructor() {}
}

const c = ClassNameB.getInstance();
const d = ClassNameB.getInstance();

console.log(c === d); // true

 

11. 상속(Inheritance)

클래스가 다른 클래스를 가져다가 자신만의 기능을 추가 하는 것

class Parent {
    //protected는 상속관계에서 접근 가능)
    constructor(protected _name:string, private _age:number) {}

    public print():void {
        console.log(`name : ${this._name}, age : ${this._age}`);
    }
}

//Parent는 new로 직접 생성도 가능
const p = new Parent('Hong', 37);
p.print()

class Children extends Parent {
    public gender = "male";
    constructor(age:number) {
        //자식에서 constuctor을 사용할 경우 super를 이용해서 부모의 constructor을 호출해줘야한다.
        //super를 맨 먼저 호출해줘야한다.
        super("Yeol", age)
    }
    
}

const c = new Children(5);
c.print()

12. Abstract Classes

완전하지 않은 클래스표현, 

new를 이용해서 객체 생성 불가 -> 상속을 해서 완전한 클래스로 만들고 나서 사용해야된다. 

abstract class AbstractPerson {
    protected _name:string = "Mark";

    abstract setName(name:string):void;
}

// new AbstractPerson() 불가...완전한 class가 아니다..

class Person extends AbstractPerson {
    setName(name: string): void {
        this._name = name
        //throw new Error("Method not implemented.");
    }
    printName() {
        console.log(this._name)
    }
}

const p1 = new Person();
p1.setName("Hong")
p1.printName();