ES6 클래스와 그 이후 발전 (ES6 Classes and Beyond)

ES6 클래스와 그 이후 발전

ES6 클래스와 그 이후 발전

1. ES6 클래스란 무엇인가?

ES6(ECMAScript 2015)에서 도입된 클래스(Class)는 JavaScript에서 객체 지향 프로그래밍(OOP)을 직관적이고 간결하게 구현하기 위한 문법적 설탕입니다. 기존 프로토타입 기반 상속을 더 읽기 쉽게 포장한 형태로, class 키워드를 사용하여 정의됩니다.

기본 문법:


class ClassName {
  constructor(param1, param2) {
    this.param1 = param1;
    this.param2 = param2;
  }

  methodName() {
    return `${this.param1} and ${this.param2}`;
  }
}
        

예시:


class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    return `Hello, I'm ${this.name}!`;
  }
}

const person = new Person("Alice", 30);
console.log(person.greet()); // Hello, I'm Alice!
        

2. ES6 클래스의 주요 특징

  • 선언적 문법: OOP에 익숙한 개발자에게 친숙하며 가독성 향상.
  • 생성자: 단일 constructor로 인스턴스 초기화.
  • 프로토타입 기반: 내부적으로 프로토타입 상속 사용.
  • 정적 메서드/속성: 클래스 자체에 속하는 기능 제공.

예시: 정적 메서드 (MathUtils)

MathUtils는 인스턴스 생성 없이 정적 메서드만 제공하는 유틸리티 클래스입니다. constructor에서 에러를 발생시켜 인스턴스화를 방지합니다.


class MathUtils {
  constructor() {
    throw new Error("MathUtils is a static class");
  }

  static square(num) {
    return num * num;
  }

  static cube(num) {
    return num * num * num;
  }

  static isEven(num) {
    return num % 2 === 0;
  }
}

console.log(MathUtils.square(4)); // 16
console.log(MathUtils.cube(3)); // 27
console.log(MathUtils.isEven(6)); // true
// const util = new MathUtils(); // Error: MathUtils is a static class
        

MathUtils 설명: MathUtils는 유틸리티 함수를 논리적으로 그룹화하며, constructor에서 throw new Error("MathUtils is a static class")를 호출하여 인스턴스 생성을 차단합니다. 이는 상태 관리가 불필요한 경우 전역 스코프 오염을 방지하고 명확한 API를 제공합니다.

3. ES6 이후 클래스 관련 발전

3.1. 공개/비공개 필드 (ES2020, ES2022)

공개 필드는 생성자 외부에서 선언 가능하며, 비공개 필드는 # 접두사로 캡슐화합니다.


class Counter {
  count = 0;
  #privateCount = 0;
  static maxCount = 100;

  increment() {
    this.count++;
    this.#privateCount++;
    return this.count;
  }

  getPrivateCount() {
    return this.#privateCount;
  }
}

const counter = new Counter();
console.log(counter.count); // 0
console.log(counter.increment()); // 1
console.log(counter.getPrivateCount()); // 1
// console.log(counter.#privateCount); // SyntaxError
console.log(Counter.maxCount); // 100
        

3.2. 정적 초기화 블록 (ES2022)

static 블록으로 정적 속성을 초기화합니다.


class Database {
  static #connection = null;

  static {
    this.#connection = `Connected to ${Math.random()}`;
  }

  static getConnection() {
    return this.#connection;
  }
}

console.log(Database.getConnection()); // Connected to 
        

3.3. 클래스 표현식 (ES6)

클래스를 함수 표현식처럼 정의 가능합니다.


const MyClass = class {
  constructor(value) {
    this.value = value;
  }
};

const instance = new MyClass(42);
console.log(instance.value); // 42
        

3.4. Getter와 Setter

getset으로 속성 접근 제어.


class User {
  #name;

  constructor(name) {
    this.#name = name;
  }

  get name() {
    return this.#name;
  }

  set name(value) {
    if (value.length < 2) throw new Error("Name too short");
    this.#name = value;
  }
}

const user = new User("Bob");
console.log(user.name); // Bob
user.name = "Alice"; // 성공
// user.name = "A"; // Error: Name too short
        

3.5. 메서드 체이닝

메서드가 this를 반환하여 체이닝 지원.


class Calculator {
  constructor(value = 0) {
    this.value = value;
  }

  add(num) {
    this.value += num;
    return this;
  }

  subtract(num) {
    this.value -= num;
    return this;
  }

  getResult() {
    return this.value;
  }
}

const calc = new Calculator();
console.log(calc.add(5).subtract(2).getResult()); // 3
        

4. 언제 클래스를 사용해야 할까?

  • OOP 설계: 캡슐화 구현.
  • 가독성: 복잡한 프로토타입 코드를 간소화.
  • 재사용: 객체 템플릿 생성.
  • 캡슐화: 비공개 필드로 데이터 보호.
  • 유틸리티 그룹화: MathUtils처럼 정적 메서드로 함수 조직화.

예시: 쇼핑카트


class ShoppingCart {
  #items = [];

  addItem(item, price) {
    this.#items.push({ item, price });
    return this;
  }

  getTotal() {
    return this.#items.reduce((sum, { price }) => sum + price, 0);
  }

  getItems() {
    return [...this.#items];
  }
}

const cart = new ShoppingCart();
cart.addItem("Apple", 1).addItem("Banana", 2);
console.log(cart.getTotal()); // 3
console.log(cart.getItems()); // [{item: "Apple", price: 1}, {item: "Banana", price: 2}]
        

5. 언제 클래스를 피해야 할까?

  • 간단한 로직: 유틸리티 함수로 충분한 경우.
  • 동적 프로토타입: 동적 수정이 필요한 경우.
  • 성능 최적화: 미세한 최적화가 필요한 경우.

// 클래스 불필요
function add(a, b) {
  return a + b;
}

// 클래스 오버헤드
class Adder {
  add(a, b) {
    return a + b;
  }
}
        

6. 정적 클래스의 대안

MathUtils 같은 정적 클래스는 유틸리티 함수를 그룹화하지만, 대안도 존재합니다:

  • 객체 리터럴: 간단한 함수 그룹화.
  • 모듈 패턴: 비공개 데이터 지원.
  • 함수 네임스페이스: ES6 이전 스타일.

// 객체 리터럴
const MathUtilsObj = {
  square(num) {
    return num * num;
  }
};

console.log(MathUtilsObj.square(5)); // 25
        

7. 결론

ES6 클래스는 객체 지향 프로그래밍을 간결하게 만들며, 비공개 필드, 정적 초기화 블록, 정적 메서드 등으로 강력해졌습니다. MathUtils 같은 정적 클래스는 유틸리티 함수를 조직화하며 전역 스코프 오염을 방지합니다. 복잡한 객체 설계나 캡슐화가 필요한 경우에 적합하며, 간단한 로직에는 함수를 고려하세요.

댓글 없음:

댓글 쓰기

댓글 폭탄 해결! 자바스크립트 댓글 접기/펼치기로 가독성 200% 높이는 법(Solve Comment Chaos: Elevate Readability 200% with JS Comment Folding/Unfolding)

내 웹사이트에 적용! 초간단 자바스크립트 댓글 펼치기/숨기기 튜토리얼 내 웹사이트에 적용! 초간단 자바스크립트 댓글 펼치기/숨기기 튜토...