class
class (클래스 선언)
클래스는 객체를 만드는 템플릿입니다. 데이터를 해당 데이터를 다루는 코드로 캡슐화합니다. JS의 클래스는 프로토타입 위에 구축되지만, 클래스에만 고유한 일부 문법과 의미론도 갖습니다. 원문은 MDN의 JavaScript 참고 문서이자 클래스 디렉터리 페이지입니다.
본문
클래스는 객체를 만드는 템플릿입니다. 데이터와 그 데이터를 처리하는 코드를 함께 캡슐화합니다. JavaScript의 클래스는 프로토타입(prototype) 위에 구축되지만, 클래스에만 고유한 문법과 의미론도 있습니다. 더 많은 예제와 설명은 Using classes 가이드를 참고하세요.
클래스 정의 (Defining classes)
클래스는 사실 "특별한 함수"입니다. 함수 표현식과 함수 선언을 정의할 수 있는 것처럼, 클래스도 클래스 표현식(class expression)이나 클래스 선언(class declaration) 두 가지 방식으로 정의할 수 있습니다.
// 선언 (Declaration)
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
// 표현식; 클래스는 익명이지만 변수에 할당됨
const Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
// 표현식; 클래스가 고유한 이름을 가짐
const Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
함수 표현식처럼 클래스 표현식은 익명일 수도 있고, 할당된 변수와 다른 이름을 가질 수도 있습니다. 그러나 함수 선언과 달리 클래스 선언은 let이나 const와 같은 temporal dead zone(시간적 사각지대) 제약을 가지며, 호이스팅되지 않는 것처럼 동작합니다.
클래스 본문 (Class body)
클래스의 본문은 중괄호 {} 안의 부분입니다. 여기서 메서드나 constructor 같은 클래스 멤버를 정의합니다. 클래스 본문은 "use strict" 지시어가 없어도 strict mode(엄격 모드)로 실행됩니다.
클래스 요소(element)는 세 가지 측면으로 특성화할 수 있습니다.
- 종류(Kind): getter, setter, method, field
- 위치(Location): static 또는 instance
- 가시성(Visibility): public 또는 private
이들은 합쳐져 총 16가지 조합이 됩니다. 참고를 더 논리적으로 나누고 내용 중복을 피하기 위해, 각 요소는 별도 페이지에서 자세히 다룹니다 — method definitions, getter, setter, public class fields, static, private elements 등.
참고: private 요소는 같은 클래스에서 선언된 모든 private 이름이 고유해야 한다는 제약이 있습니다. 다른 모든 public 속성에는 이런 제약이 없어서, 같은 이름의 public 속성을 여러 개 가질 수 있으며 마지막 것이 나머지를 덮어씁니다. 이는 객체 이니셜라이저와 같은 동작입니다.
또한 constructor와 static initialization blocks 두 가지 특별한 클래스 요소 문법이 있으며 각각 고유한 참고 문서가 있습니다.
생성자 (Constructor)
constructor 메서드는 클래스로 생성된 객체를 만들고 초기화하는 특별한 메서드입니다. 클래스에는 "constructor"라는 이름의 특별한 메서드가 하나만 있을 수 있습니다 — 클래스에 constructor 메서드가 두 번 이상 나타나면 SyntaxError가 발생합니다. 생성자는 super 키워드를 사용해 상위 클래스의 생성자를 호출할 수 있습니다. 생성자 안에서 인스턴스 속성을 만들 수 있습니다.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
인스턴스 속성의 값이 생성자의 인자에 의존하지 않는다면, 이를 클래스 필드(class field)로 정의할 수도 있습니다.
정적 초기화 블록 (Static initialization blocks)
정적 초기화 블록은 정적 속성의 유연한 초기화를 허용합니다. 초기화 중 문(statement)을 평가하는 것도 포함하며, private 스코프에 접근 권한을 부여합니다. 여러 정적 블록을 선언할 수 있고, 정적 필드와 메서드의 선언과 섞어서 쓸 수 있습니다(모든 정적 항목은 선언 순서대로 평가됩니다).
메서드 (Methods)
메서드는 각 클래스 인스턴스의 프로토타입에 정의되며 모든 인스턴스가 공유합니다. 메서드는 일반 함수, async 함수, 생성기 함수, 또는 async 생성기 함수일 수 있습니다.
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
*getSides() {
yield this.height;
yield this.width;
yield this.height;
yield this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
console.log([...square.getSides()]); // [10, 10, 10, 10]
정적 메서드와 필드 (Static methods and fields)
static 키워드는 클래스의 정적 메서드 또는 필드를 정의합니다. 정적 속성(필드와 메서드)은 각 인스턴스가 아니라 클래스 자체에 정의됩니다. 정적 메서드는 애플리케이션의 유틸리티 함수를 만드는 데 자주 사용되며, 정적 필드는 캐시, 고정 구성, 또는 인스턴스 간에 복제할 필요가 없는 데이터에 유용합니다.
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static displayName = "Point";
static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; // undefined
p1.distance; // undefined
console.log(Point.displayName); // "Point"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
필드 선언 (Field declarations)
클래스 필드 선언 문법을 사용하면 위 생성자 예제를 다음과 같이 쓸 수 있습니다.
class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
클래스 필드는 변수가 아니라 객체 속성과 비슷하므로, 선언할 때 const 같은 키워드를 사용하지 않습니다. JavaScript에서 private 요소는 특별한 식별자 문법을 사용하므로 public이나 private 같은 수식어 키워드도 사용하면 안 됩니다. 위에서 보듯 필드는 기본값이 있거나 없이 선언할 수 있으며, 기본값이 없으면 undefined로 기본 설정됩니다. 필드를 미리 선언하면 클래스 정의가 더 자명해지고 필드가 항상 존재하게 되어 최적화에 도움이 됩니다.
Private 요소 (Private elements)
private 필드를 사용하면 정의를 다음과 같이 다듬을 수 있습니다.
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
클래스 밖에서 private 필드를 참조하는 것은 오류이며, private 필드는 클래스 본문 안에서만 읽거나 쓸 수 있습니다. 클래스 밖에 보이지 않는 것들을 정의함으로써 클래스 사용자가 버전마다 바뀔 수 있는 내부 구현에 의존하지 못하게 합니다. private 필드는 필드 선언에서 미리 선언되어야만 하며, 일반 속성이 그렇듯 나중에 할당을 통해 생성할 수 없습니다. private 메서드와 접근자(accessor)도 public 대응 문법과 같은 문법으로 정의하되 식별자를 #로 시작하면 됩니다.
상속 (Inheritance)
extends 키워드는 클래스 선언이나 클래스 표현식에서, 다른 생성자(클래스 또는 함수)의 자식 클래스를 만들 때 사용합니다.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // super 클래스 생성자를 호출하고 name 인자를 전달
}
speak() {
console.log(`${this.name} barks.`);
}
}
const d = new Dog("Mitzie");
d.speak(); // "Mitzie barks."
사양 및 호환성
클래스는 ECMAScript 사양에서 정의되며, Baseline "Widely available"로 분류되어 2016년 3월부터 브라우저 전반에서 사용 가능했습니다.
더 알아보기
- class (클래스 선언 문)
- class 표현식
- constructor
- extends
- static
- Private elements
- Using classes 가이드