클래스와 객체지향 — class·extends·this
class 문법, 상속, getter/setter, #private 까지.
JS 의 class 는 ES2015 부터의 표준 — 사실은 프로토타입(23편) 위의 문법적 설탕이지만, 사용자 입장에선 Java·Python 같은 모양. 18편은 class 의 모든 핵심 문법을 정리합니다. TS 8편 의 비교편으로 봐도 좋아요.
기본 형태
class User {
// 필드 선언 (ES2022+)
active = true;
// 생성자
constructor(name, age) {
this.name = name;
this.age = age;
}
// 메서드
greet() {
return `Hi, ${this.name}!`;
}
// 정적 메서드 (클래스 자체에 붙음)
static fromJSON(json) {
return new User(json.name, json.age);
}
}
const u = new User("준성", 39);
u.greet(); // "Hi, 준성!"
User.fromJSON({...}); // 정적
getter · setter — 메서드처럼 보이는 속성
class User {
#firstName = "";
#lastName = "";
constructor(first, last) {
this.#firstName = first;
this.#lastName = last;
}
get fullName() {
return `${this.#firstName} ${this.#lastName}`;
}
set fullName(value) {
[this.#firstName, this.#lastName] = value.split(" ");
}
}
const u = new User("준성", "박");
u.fullName; // "준성 박" (메서드 호출 () 없음)
u.fullName = "준석 박"; // setter 호출
u.fullName; // "준석 박"
#private — 진짜 비공개 필드 (ES2022+)
class Account {
#balance = 0; // # 접두사 — 진짜 private
#pin;
constructor(pin) {
this.#pin = pin;
}
deposit(amount) {
this.#balance += amount;
}
checkBalance(pin) {
if (pin !== this.#pin) throw new Error("PIN 틀림");
return this.#balance;
}
}
const a = new Account("1234");
a.deposit(1000);
a.#balance; // ❌ SyntaxError — 클래스 밖에선 접근 불가 (TS 의 private 와 달리 런타임 강제)
TS private vs JS #private. TS 의 private 는 컴파일 시점만 — 런타임에는 일반 속성처럼 우회 가능. JS 의 #field 는 언어 차원의 진짜 비공개. 새 코드는 #field 권장.
extends · super — 상속
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} 가 소리냄`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // 부모 생성자 호출 (필수, this 사용 전)
this.breed = breed;
}
speak() { // 오버라이드
return `${this.name} 짖기!`;
}
describe() {
return `${super.speak()} — 종: ${this.breed}`;
// ^ 부모 메서드 호출
}
}
const d = new Dog("초코", "리트리버");
d.speak(); // "초코 짖기!"
d.describe(); // "초코 가 소리냄 — 종: 리트리버"
super() 호출 순서. 자식 constructor 에서 this 사용 전 반드시 super(). 안 하면 ReferenceError. extends 가 있으면 super 가 필수.
static — 클래스 레벨
class MathUtils {
static PI = 3.14159; // static 필드
static circleArea(r) { // static 메서드
return MathUtils.PI * r * r;
}
// static block (ES2022) — 클래스 초기화
static {
console.log("MathUtils 로드됨");
}
}
MathUtils.PI; // 3.14159
MathUtils.circleArea(5); // 78.54
// 인스턴스에서는 접근 X
new MathUtils().PI; // undefined
this 의 함정 — 분리하면 잃음
class Counter {
count = 0;
increment() {
this.count++;
}
}
const c = new Counter();
c.increment(); // OK
const fn = c.increment; // 메서드를 변수에
fn(); // ❌ TypeError — this 잃음
// 해결 1: 명시적 bind
const fn = c.increment.bind(c);
fn(); // OK
// 해결 2: 화살표 함수 필드 (this 가 인스턴스에 고정)
class Counter {
count = 0;
increment = () => { // 화살표 — this 가 인스턴스로 자동 캡처
this.count++;
};
}
const fn = new Counter().increment;
fn(); // OK
React 이벤트 핸들러·setTimeout 콜백 등에서 가장 자주 만나는 함정. 22편(this) 에서 깊이.
instanceof — 인스턴스 확인
class Cat extends Animal { }
const c = new Cat("나비");
c instanceof Cat; // true
c instanceof Animal; // true (상속)
c instanceof Object; // true (모든 객체)
// 사용
function feed(x) {
if (x instanceof Animal) x.eat();
}
믹스인 — 다중 상속의 대안
// JS 는 단일 상속만. 여러 능력 합치고 싶으면 믹스인
function Loggable(Base) {
return class extends Base {
log(msg) { console.log(`[${this.constructor.name}] ${msg}`); }
};
}
function Serializable(Base) {
return class extends Base {
toJSON() { return JSON.stringify(this); }
};
}
class User extends Loggable(Serializable(Object)) {
constructor(name) { super(); this.name = name; }
}
const u = new User("준성");
u.log("hi"); // [User] hi
u.toJSON(); // '{"name":"준성"}'
클래스 vs 함수 + 객체 — 언제 클래스?
실전 가이드. 다음 중 2개 이상 해당하면 클래스, 아니면 함수 + 객체 리터럴.
① 인스턴스가 여러 개 생성됨 (User 객체 N 개).
② 상태(필드) 가 있고 메서드들이 그 상태를 다룸.
③ 상속·다형성이 자연스러움.
한 가지만 — 함수 + 클로저 또는 객체 리터럴이 더 가볍습니다. React 함수형 컴포넌트가 그 예.
한 표 — 멤버 종류
| 종류 | 예시 | 특징 |
|---|---|---|
| 인스턴스 필드 | x = 0; | 매 인스턴스 |
| 인스턴스 메서드 | greet() { } | 프로토타입에 한 번 |
| 정적 필드 | static C = 1; | 클래스 자체 |
| 정적 메서드 | static of() { } | 클래스 자체 |
| getter/setter | get x() / set x(v) | 속성처럼 접근 |
| private 필드 | #secret = 0; | 진짜 비공개 (ES2022) |
| static block | static { ... } | 클래스 초기화 (ES2022) |
19편 — 모듈 (import·export·번들러)
ESM/CJS, default vs named, 트리 셰이킹.
📚 쉽게 배우는 자바스크립트 교재
이전: 17편 fetch · 현재: 18편 (중급) · 다음 → 19편 모듈 · 진행: 18/26
이전: 17편 fetch · 현재: 18편 (중급) · 다음 → 19편 모듈 · 진행: 18/26