25장 클래스

이번 장에서는 자바스크립트에서의 클래스에 대해 살펴보고, 타입스크립트와의 차이점에 대해서도 추후 생각해보겠다.

25.1 클래스는 프로토타입의 문법적 설탕인가?

// ES5 생성자 함수
var Person = (function () {
    // 생성자 함수
    function Person(name) {
    this.name = name;
    }
    // 프로토타입 메서드
    Person.prototype.sayHi = function () {
    console.log('Hi! My name is ' + this.name);
    }
    // 생성자 함수 반환
    return Person;
}())
// 인스턴스 생성
var me = new Person( Lee );
me.sayHi(); // Hi! My name is Lee

25.2 클래스 정의

// 클래스 선언문
class Person {}
// 익명 클래스 표현식
const Person = class {};
// 기명 클래스 표현식
const Person = class MyClass {};

// 클래스 선언문
class Person {
// 생성자
constructorname {
    // 인스턴스 생성 및 초기화
    this.name = name; // name 퍼티는 public하다.
}
// 프로토타입 메서드
sayHi() {
    console.log('Hi! My name is ${this.name}');
}
// 정적 머/서드
static sayHello() {
    console.log('Hello! );
}
}
// 인스턴스 생성
const me = new Person('Lee');
// 인스턴스의 프로퍼티 참조
console.log(me.name); // Lee
// 프로토타입 메서드 호출
me. sayHi(); // Hi! My name is Lee
// 정적 메서드 호출
Person.sayHello(); // Hello!

25.4 인스턴스 생성

class Person {}
// 인스턴스 생성
const me = new Person();
console.log(me); // Person {}

25.5 메서드

25.5.1 constructor
25.5.2 프로토타입 메서드
// 생성자 함수
function Person(name) {
    this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHi = function () {
    console.log( Hi! My name is ${this.name} );
}
const me = new Person('Lee');
me.sayHi(); // Hi! My name is Lee

// me 객체의 프로토타입은 Person.prototype이다.
Object.getPrototypeOf(me) === Person.prototype; // — true
me instanceof Person; // — true
// Person.prototype의 프로토타입은 Object.prototype이다.
Object.getPrototypeOf(Person.prototype) === Object.prototype; // — true
me instanceof Object; // — true
// me 객체의 constructor는 Person 클래스다.
me.constructor == Person; // — true
25.5.3 정적 메서드
class Person {
    // 생성자
    constructor(name) {
        // 인스턴스 생성 및 초기화
        this.name = name;
    }
    // 정적 메서드
    static sayHi() {
        console.log('Hi!')
    }
}
// 정적 메서드는 클래스로 호출한다.
// 정적 메서드는 인스턴스 없이도 호출할 수 있다.
Person.sayHi(); // Hi!
25.5.4 정적 메서드와 프로토타입 메서드의 차이
// 표준 빌트인 객체의 정적 메서드
Math.max(1, 2, 3); // — 3
Number.isNaN(NaN) // — true
JSON.stringify({ a: 1 }); // — "{"a":l}"
Object.is({}, {}); // — false
Reflect.has({ a 1 }, 'a') // — true

25.6 클래스의 인스턴스 생성 과정

class Person {
// 생성자
    constructor(name) {
        // 1. 암묵적으로 인스턴스가 생성되고 thisotl 바인딩된다.
        console.log(this); // Person {}
        console.log(Object.getPrototypeOf(this) === Person.prototype); // true
        // 2. this에 바인딩되어 있는 인스턴스를 초기화한다.
        this.name = name;
        // 3. 완성된 인스턴스가 바인딩된 this가 암묵적으로 반환된다.
    }
}

25.7 프로퍼티

25.7.1 인스턴스 프로퍼티
class Person {
    constructor(name) {
        // 인스턴스 프로퍼티
        this.name = name;
    }
}
const me = new Person( 'Lee');
console.log(me); // Person {name: "Lee"}
25.7.2 접근자 프로퍼티
class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    // fullName은 접근자 함수로 구성된 접근자 프로퍼티다.
    // getter 함수
    get fullName() {
     return '${this.firstName} ${this.lastName}';
    }
    // setter 함수
    set fullName(name) {
      [this.firstName, this.lastName] = name.split(' ');
    }
}
const me = new Person('Ungmo', 'Lee' );
// 데이터 프로퍼티를 통한 프로퍼티 값의 참조.
console.log('${me.firstName} ${me.lastName}'); // Ungmo Lee
// 접근자 프로퍼티를 통한 프로퍼티 값의 저장
// 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출된다.
me.fullName = Heegun Lee1;
console.log(me); // {firstName: "Heegun", lastName: "Lee"}
// 접근자 프로퍼티를 통한 프로퍼티 값의 참조
// 접근자 프로퍼티 fullName어/ 접근하면 getter 함수가 호출된다.
console.log(me.fullName); // Heegun Lee
// fullName은 접근자 프로퍼티다.
11 접근자 프로퍼티는 get, set, enumerable, configurable 프로퍼티 어트리뷰트를 갖는다.
console.log(Object.getOwnPropertyDescriptor(Person.prototype, 'fullName'));
// {get: f, set: f, enumerable: false, configurable: true}
25.7.3 클래스 필드 정의 제안
class Person {
    // this에 클래스 필드를 바인딩해서는 안 된다.
    this.name =''; // SyntaxError: Unexpected token '
}
class Person {
    // 클래스 필드
    name = 'Lee';
    constructor() {
        console.log(name); // ReferenceError: name is not defined
    }
}
new Person();
class Person {
    // 클래스 필드에 문자열을 할당
    name = 'Lee';
    // 클래스 필드에 함수를 할당
    getName = function () {
        return this.name;
    }
    // 화살표 함수로 정의할 수도 있다.
    // getName = () => this.name;
}
const me = new Person();
console.log(me); // Person {name: "Lee", getName: f}
console.log(me.getName()); // Lee
- 
25.7.4 private 필드 정의 제안
class Person {
    // private 필드 정의
    #name = '';
    constructor(name) {
    // private 필드 참조
    this.#name = name;
    }
}
const me = new Person('Lee');
// private 필드 #name은 클래스 외부에서 잠조할 수 없다.
console.log(me.#name);
// SyntaxError: Private field 'tfname' must be declared in an enclosing class
타입스크립트
class Person {
    // private 필드 정의
    #name = ' ' :
    constructor(name) {
        this.#name = name;
    }
    // name은 접근자 프로퍼티다.
    get name() {
        // private 필드를 참조하여 trim한 다음 반환한다.
        return this.#name.trim();
    }
}
const me = new Person(' Lee 1);
console.log(me.name); // Lee
25.7.5 static 필드 정의 제안

25.8 상속에 의한 클래스 확장

25.8.1 클래스 상속과 생성자 함수 상속
25.8.2 extends 키워드
// 수퍼(베아스/부모)클래스
class Base {}
// 서브(파생/자식)클래스
class Derived extends Base {}
25.8.3 동적 상속
// 생성자 함수
function Base(a) {
    this.a = a;
}
// 생성자 함수를 상속받는 서브클래스
class Derived extends Base {}
const derived = new Derived(l);
console.log(derived); // Derived {a: 1}
25.8.4 서브 클래스의 constructor
constructor() {}
constructor( ... args) { super( ... args); }
25.8.5 super 키워드
25.8.6 상속 클래스의 인스턴스 생성 과정
// 수퍼클래스
class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }
    getArea() {
        return this.width * this.height;
    }
    toString() {
     return width = ${this.width}, height = ${this.height} ;
    }
}
// 서브클래스
class ColorRectangle extends Rectangle {
    constructor(width, height, color) {
        super(width, height);
        this.color = color;
    }
    // 머/서드 오버라이딩
    toString() {
        return super.toString() + color = ${this.color} ;
    }
}
const ColorRectangle = new ColorRectangle(2, 4, ' red');
console.log(ColorRectangle); // ColorRectangle {width: 2, height: 4, color: "red"}
// 상속을 통해 getArea 메서드를 호출
console.log(ColorRectangle.getArea()); // 8
// 오버라이딩된 toString 메서드를 호출
console. log( ColorRectangle. toString()); // width = 2, height = 4, color = red

1) 서브클래스의 super 호출

2) 수퍼클래스의 인스턴스 생성과 this 바인딩

3) 수퍼클래스의 인스턴스 초기화

4) 서브클래스 constructor로의 복귀와 this 바인딩

// 서브클래스
class ColorRectangle extends Rectangle {
    constructor(width, height, color) {
    super(width, height);
    // super가 반환한 인스턴스가 this에 바인딩된다.
    console.log(this); // ColorRectangle {width: 2, height: 4}
    ...

5) 서브클래스의 인스턴스 초기화

6) 인스턴스 반환

끝!