본문 바로가기
TYPESCRIPT

클래스 1

by 일태찡 2023. 3. 20.

 

클래스란

 

  • 클래스는 객체의 청사진입니다.
  • 클래스를 기반으로 하는 객체를 쉽게 만들 수 있으려면 어떤 메서드가 필요한지 정의할 수 있기 때문에 이를 클래스 내의 인스턴스라고 부릅니다. 따라서 객체는 클래스 내의 인스턴스입니다.
  • 클래스를 기반으로 하면 동일한 구조, 동일한 클래스를 기반으로 하는 동일한 메서드로 여러 객체를 빠르게 복제할 수 있습니다.
  • 클래스는 객체의 형태, 포함해야 할 속성과 메서드를 정의하는 데 도움이 되며 객체에 저장된 정확한 데이터 세부 정보만 다를 뿐입니다.
  • 여러 사람들을 객체로 사용하여 표현하고자 한다면 사람들은 각각 이름과 나이가 다르지만 일반적인 구조는 같은 것입니다.

 

 

클래스 만들기

 

app.ts

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

const accounting = new Department('Accounting');

console.log(accounting);

 

기본적인 클래스를 만드는 코드입니다.

Department(부서) 클래스를 열어 그 필드 안에 이름의 타입을 배정하고 생성자 함수를 통해 그 이름을 인수로 받았습니다.

 

app.js

"use strict";
class Department {
    constructor(n) {
        this.name = n;
    }
}
const accounting = new Department('Accounting');
console.log(accounting);
//# sourceMappingURL=app.js.map

 

위 코드를 자바스크립트로 컴파일하면 이렇게 번역되며 약간 다르지만 매우 비슷한 형태를 띠고 있습니다.

지금까진 es6 자바스크립트로 컴파일해 왔고 세팅은 아래와 같습니다.

 

tsconfig.json

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "lib": [
      "dom",
      "es6",
      "dom.iterable",
      "scripthost"
    ],
  ...
}

 

이를 es5 자바스크립트로 컴파일하기 위해 target을 "es5"로 바꾸고 lib과 관련된 내용을 모두 주석처리 해줍니다.

target은 어떤 버전으로 컴파일을 할 것인지 설정하는 것이고 lib은 타입스크립트가 이해할 수 있는 식별자를 설정하는 것입니다.

 

tsconfig.json

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    // "lib": [
    //   "dom",
    //   "es6",
    //   "dom.iterable",
    //   "scripthost"
    // ],
  ...
}

 

위의 설정으로 자바스크립트로 컴파일하면 생성자 함수가 사라지고 그 함수가 반환문이 생겼습니다.

코드의 차이는 있지만 모두 근본적으로 자바스크립트에서 생성자 함수를 만드는 게 가능했습니다.

 

app.js

"use strict";
var Department = (function () {
    function Department(n) {
        this.name = n;
    }
    return Department;
}());
var accounting = new Department('Accounting');
console.log(accounting);
//# sourceMappingURL=app.js.map

 

자바스크립트가 최신화되고 타입스크립트가 생기면서 코드가 간결해지긴 했지만 이 클래스 개념은 오래전부터 사용되었던 걸 나타냅니다.

 

 

this 키워드

 

app.ts

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

    // 메소드
    describe() {
        console.log('Department: ' + this.name)
    }
}

const accounting = new Department('Accounting');

accounting.describe(); // Department: Accounting

const accountingCopy = { describe: accounting.describe};

accountingCopy.describe(); // Department: undefined

 

위의 코드를 메서드를 생성하여 다르게 표현했습니다.

그러나 카피본을 만들고 그 메서드를 참조하게 했지만 name을 불러오지 못하고 undefined가 뜨게 되었습니다.

이는 accountingCopy 객체의 name에 접근하게 설정되어 있기 때문입니다.

 

app.ts

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

    describe(this: Department) { // 매개변수 추가
        console.log('Department: ' + this.name)
    }
}

const accounting = new Department('Accounting');

accounting.describe(); // Department: Accounting

const accountingCopy = { name: 'Marketing', describe: accounting.describe}; // name 속성 추가

accountingCopy.describe(); // Department: Marketing

 

이렇게 메서드에 this를 매개변수로 추가하고 복제에 name 속성을 추가하여 해결할 수 있었습니다.

 

 

private 수정자

 

private의 의미는 클래스, 즉, 생성된 객체 내부에서만 접근할 수 있는 속성이 되었다는 것을 의미합니다.

따라서 부서 클래스 내의 어떤 메서드로든 접근할 수 있지만, 다르게는 접근할 수 없게 됩니다.

 

app.ts

class Department {
    public name: string;
    private employees: string[] = []; // private 액세스 수정자
    
    constructor(n: string) {
        this.name = n;
    }

    describe(this: Department) {
        console.log('Department: ' + this.name)
    }

    addEmployee(employee: string) {
        this.employees.push(employee)
    }

    printEmployeeInformation() {
        console.log(this.employees.length);
        console.log(this.employees)
    }
}

const accounting = new Department('Accounting');

accounting.addEmployee('KIM');
accounting.addEmployee('PARK');

accounting.employees[2] = 'SON'; // 에러
accounting.name = 'Marketing'; // 에러 아님

 

위의 예시를 보면 private가 없었다면 두 방법 모두 employees에 접근할 수 있었지만 private로 선언했기에 메서드로는 접근할 수 있지만 두 번째 방법으로는 접근할 수 없습니다.

 

 

이와 다르게 쓰지 않아도 기본으로 설정된 public이 있으며 이는 외부에서도 접근할 수 있다는 것입니다.

이는 자바스크립트에서는 잡아줄 수 없는 기능이기에 타입스크립트에서만 지원하며 컴파일 에러는 발생하나 런타임 에러는 발생하지 않게 됩니다.

자바스크립트는 모두 public으로만 판단하고 넘어가게 됩니다.

 

 

이중 초기화 방지

 

app.ts

class Department {
    // private id: string;
    // public name: string;
    private employees: string[] = [];
    
    constructor(private id: string, public name: string) { // 여기
        this.id;
        this.name;
    }

    describe(this: Department) {
        console.log(`Department (${this.id}): ${this.name}`);
    }
}

 

생성자 함수에 매개 변수로 위의 선언된 속성들을 가져와 이중 초기화를 막으며 코드를 간결하게 할 수 있습니다.

 

 

readonly 속성

 

app.ts

class Department {
    private employees: string[] = [];
    
    //                  여기
    constructor(private readonly id: string, public name: string) {
        this.id;
        this.name;
    }

    describe(this: Department) {
        console.log(`Department (${this.id}): ${this.name}`);
    }

    addEmployee(employee: string) {
        this.id = 'A2'; // 에러
        this.employees.push(employee)
    }

    printEmployeeInformation() {
        console.log(this.employees.length);
        console.log(this.employees)
    }
}

 

readonly는 특정 속성이 초기화되고 나면 이후에는 변경되어서는 안 된다는 점을 명확히 할 수 있습니다.

 

 

 

상속

 

고유의 특정 속성과 메서드를 갖는 클래스도 있는데 그때 상속이 유용합니다.

 

app.ts

class ITDepartment extends Department {
    constructor (id: string, public admins: string[]) {
        super(id, 'IT');
        this.admins = admins;
    }
}

const newIT = new ITDepartment('B1', ['LEE']);

 

super는 기본 클래스의 생성자를 호출하며 다음 작업을 수행하기 전에 항상 먼저 호출해야 합니다.

 

 

 

protected 수정자

 

app.ts

class Department {
    private employees: string[] = [];
    // protected employees: string[] = [];
    
    constructor(private readonly id: string, public name: string) {
        this.id;
        this.name;
    }

    describe(this: Department) {
        console.log(`Department (${this.id}): ${this.name}`);
    }

    addEmployee(employee: string) {
        this.employees.push(employee)
    }

    printEmployeeInformation() {
        console.log(this.employees.length);
        console.log(this.employees)
    }
}


class AccountingDepartment extends Department {
    constructor(id: string, private reports: string[]) {
        super(id, 'Accouting');
    }
    
    addEmployee(name: string) {
        if( name === 'KIM') {
            return;
        }
        this.employees.push(name); // 에러
    }
}

 

private 속성은 정의된 클래스 내에서만 접근 가능하며 해당 클래스로부터 상속받는 클래스에서는 불가능합니다.

 

 

상속받는 클래스에서 접근할 수 있도록 하면서 외부에서 변경 불가능한 속성으로 만들고자 한다면 주석 처리 된 것처럼 private를 protected로 바꾸면 됩니다.

'TYPESCRIPT' 카테고리의 다른 글

인터페이스  (7) 2023.03.23
클래스 2  (6) 2023.03.21
타입스크립트 컴파일러  (7) 2023.03.17
타입스크립트 기초 2  (6) 2023.03.13
타입스크립트 기초 1  (7) 2023.03.09