← 글 목록

notes

25장. 클래스

모던 JS Deep Dive — 클래스 문법·상속·캡슐화와 인스턴스 핵심 정리.

참고: 이웅모 《모던 자바스크립트 Deep Dive》 25장 · [MDN Classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)

class는 프로토타입의 문법적 설탕에 가깝되, 단순 설탕만은 아니다. new 강제, 메서드 non-enumerable, extends/super, 호이스팅 TDZ, private 필드 등 안전장치·문법이 더해진 프로토타입 모델이다. 19·17을 알고 보면 class가 읽힌다.

flowchart TB
  C[class Foo] --> CTOR[constructor / [[Construct]]]
  C --> PROTO[Foo.prototype 메서드]
  C --> STATIC[정적 메서드·필드]
  SUB[class Bar extends Foo] --> SUPER[super / 체인 연결]

25.1 설탕인가?

본체는 프로토타입 위임. 다만 class는:

  • new 없이 호출하면 TypeError
  • 본문 메서드는 보통 enumerable:false
  • extends가 체인·constructor 연결을 대신 정리
  • 클래스 선언은 let/const처럼 TDZ

“완전히 새로운 객체 모델”이 아니라 “실수하기 어려운 생성자+프로토타입”.

25.2 클래스 정의

class Person {
  constructor(name) {
    this.name = name;
  }
  sayHi() {
    return `hi ${this.name}`;
  }
  static species() {
    return 'homo';
  }
}
const p = new Person('민섭');
console.log(p.sayHi(), Person.species());
console.log(Object.getPrototypeOf(p) === Person.prototype);

표현식도 가능: const C = class { … }.

25.3 클래스 호이스팅

선언은 호이스팅되나 TDZ. 선언 전 new Person은 ReferenceError. 함수 선언문처럼 끌어올려 바로 쓸 수 있다고 착각하지 말 것.

25.4 인스턴스 생성

new → 17과 같은 큰 그림(빈 객체, 프로토 연결, constructor 실행, return 규칙). class constructor는 객체를 return하면 그 객체가 될 수 있으나, 원시 return은 무시되는 감각도 유사.

25.5 메서드

constructor

인스턴스 초기화. 하나. 생략 시 빈 constructor가 있는 것과 비슷. 서브클래스는 생략 시 super(...args)를 호출하는 기본형이 들어간다.

프로토타입 메서드

sayHi()는 Person.prototype에. 인스턴스마다 함수 복사 아님.

정적 메서드

static species는 Person 함수 객체에. 인스턴스에서 안 보임(19.12).

정적 vs 프로토타입

클래스 메서드 특징

축약 메서드 → non-constructor(화살표/new 불가한 쪽). strict. enumerable false인 경우가 일반적.

25.6 인스턴스 생성 과정 (복기)

  • 새 객체, [[Prototype]] = Person.prototype
  • constructor를 this=그 객체로 실행
  • 필드 초기화(문법에 따라 순서 주의)
  • 결과 반환

25.7 프로퍼티

인스턴스 프로퍼티

constructor 안 this.x = 또는 클래스 필드 x = 1.

접근자

get/set도 프로토타입에 정의 가능.

클래스 필드

class Counter {
  n = 0;
  inc = () => { this.n += 1; }; // 인스턴스 화살표 — this 고정, 공유 X
  bump() { this.n += 1; }       // 프로토타입 공유
}

private 필드

#n — 클래스 바깥에서 접근 SyntaxError/TypeError. 인스턴스별 은닉.

class Wallet {
  #bal = 0;
  deposit(n) { this.#bal += n; }
  balance() { return this.#bal; }
}

static 필드

생성자 함수에 붙는 데이터. static #secret도 가능(환경 지원 시).

25.8 상속

extends

class Dog extends Animal — 프로토타입 체인 + 정적 체인까지 연결되는 그림.

constructor와 super

서브클래스 constructor에서 this 쓰기 전에 super(...) 필수.

class Animal {
  constructor(name) { this.name = name; }
}
class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }
  bark() { return 'wal'; }
}

super 키워드

  • constructor 안: 부모 constructor
  • 메서드 안: 부모 프로토타입 메서드 쪽 (super.hello())

동적 상속

extends 뒤에 표현식 가능(extends mix(Base)). 고급 패턴.

예제

class Stack {
  #items = [];
  push(x) { this.#items.push(x); }
  pop() { return this.#items.pop(); }
  get size() { return this.#items.length; }
}
const s = new Stack();
s.push(1); s.push(2);
console.log(s.size, s.pop());

헷갈리던 장면 / 함정

  • class를 완전히 다른 OOP로 오해
  • 필드 화살표를 남발해 메모리·상속 테스트 깨짐
  • super 전에 this
  • private을 “진짜 보안”으로 착각 — 언어 수준 은닉일 뿐
  • 호이스팅을 함수 선언과 동일시

표

질문 → 자답

Q. 생성자 함수를 버려도 되나? A. 새 코드는 class. 레거시·라이브러리·동작 이해는 프로토타입 모델 필요.

Q. 필드 vs constructor 할당? A. 필드는 선언이 한눈에. 무거운 초기화·조건은 constructor.

웹 보강 메모

MDN Classes·private fields·MDN super를 확인. 레포에서 prototype = 수동 상속을 extends로 옮길 후보를 표시.

실무로 바로

  • 도메인 타입: class
  • 공유 메서드: 프로토타입 메서드(일반 정의)
  • 리스너 this: 필드 화살표 또는 bind
  • 은닉: # 또는 모듈 스코프

new 없이 호출하면

class A {}
// A(); // TypeError: Class constructor A cannot be invoked without 'new'

생성자 함수 시절의 전역 오염 실수를 문법이 막는다(17·20).

프로토타입에 뭐가 붙나 확인

class Person {
  say() {}
  static all() {}
}
console.log(Object.getOwnPropertyNames(Person.prototype)); // constructor, say …
console.log(Object.getOwnPropertyNames(Person).includes('all')); // true
console.log(Object.keys(Person.prototype)); // [] 인 경우 많음 — enumerable false

믹스인 감각

const Speak = (Base) => class extends Base {
  speak() { return '…'; }
};
class Dog extends Speak(class {}) {}

extends 표현식으로 동적 상속. 남용 시 체인 디버깅이 어려워진다.

실무 마이그레이션

  • function Ctor + prototype → class
  • 수동 Object.create 상속 → extends
  • 클로저 은닉 → #field (또는 유지)
  • 테스트: instanceof, 메서드 공유, new 없이 호출 실패

constructor return 규칙 복습

class A {
  constructor() {
    return { hijack: true };
  }
}
console.log(new A()); // { hijack: true }

객체 return은 인스턴스를 교체할 수 있다. 실수든 팩토리 흉내든, 알고 쓸 것. 원시 return은 무시되고 원래 인스턴스가 남는다.

여기서 잠깐 💁‍♂️

26은 ES6 함수 변화(화살표·rest·파라미터 기본값). class 메서드·화살표 필드와 맞물린다.