ES6 클래스 vs 생성자 함수 - 요즘 자바스크립트에서 뭘 써야 할까?

2025. 9. 9. 15:13·FrontEnd/JavaScript

"new를 붙이면 다 같은 거 아닌가?" 싶은 그 지점부터 한 번 정리해보자 🧑‍💻

자바스크립트에서 객체를 만드는 방법은 여러 가지가 있다.

  • 리터럴 객체 {}
  • 생성자 함수 function Something() { ... }
  • ES6 클래스 class Something { ... }

겉으로 보기엔 다 비슷하게 동작하는 것 같지만,
실제로 개발할 때는 클래스 vs 생성자 함수 선택에서 꽤 차이가 난다.

이 글에서는 둘의 차이를 주니어 기준으로 정리하고,
"지금은 뭘 쓰는 게 좋은지" 감을 잡는 게 목표다.


결론 먼저

먼저 선택부터 정리하면

  • ES6 클래스
    • 문법이 직관적이고, 코드가 잘 읽힌다.
    • TypeScript와도 자연스럽게 잘 맞는다.
    • 새로 만드는 코드라면 기본값으로 이걸 쓰는 편이 좋다.
  • 생성자 함수
    • ES6 이전 스타일, 레거시 코드에서 자주 보인다.
    • prototype 설정, this 관리 등을 직접 챙겨야 한다.
    • 기존 코드 유지보수/호환용이 아니면 굳이 새로 도입할 필요는 거의 없다.

한 줄로 말하면

특별한 이유(레거시, 구형 브라우저 지원 등)가 없다면, 그냥 ES6 클래스를 쓰자


OOP(객체지향) 아주 가볍게만 짚고 가기

클래스/생성자 함수 얘기 나오면 OOP 이야기가 같이 튀어나온다.

OOP = 데이터 + 기능을 한 덩어리(객체)로 묶어서 다루는 방식

대표적으로 이런 개념들이 있다.

  1. 캡슐화:
    • 내부 데이터는 숨기고, 필요한 기능만 밖으로 노출
  2. 상속:
    • 공통 기능을 위로 올려서 재사용 (extends, prototype 등)
  3. 다형성:
    • 같은 메서드 이름인데, 구현체에 따라 다른 동작 (예: Shape.draw(), Circle.draw())

자바스크립트에서는 이걸

  • 예전에는 생성자 함수 + prototype으로 구현했고
  • ES6 이후에는 class 문법으로 더 보기 좋게 쓸 수 있게 됐다.

인스턴스란 뭐냐?

용어부터 정리해보자

인스턴스(instance) = 설계도(클래스/생성자 함수)로 찍어낸 실제 객체 한 개

비유하자면

  • 클래스/생성자 함수 = 건물 설계도
  • 인스턴스 = 그 설계도로 실제 지어진 건물 한 채

코드로 보면 이런 애들이다.

class User {}

const user1 = new User(); // user1이 User의 인스턴스
function Person() {}

const person1 = new Person(); // person1이 Person의 인스턴스

주의할 점 하나

const obj = {}; // 리터럴 객체

엄밀히 말하면 이 객체도 Object의 인스턴스이긴 하지만,
일반 대화/문서에서는 그냥 "객체"라고 부르고 굳이 인스턴스라고 부르진 않는다.


ES6 클래스 - 요즘 기본값

ES6에서 도입된 class 문법은

  • 기존의 생성자 함수 + prototype 패턴을
  • 조금 더 사람이 읽기 좋게 싸놓은 문법이라고 보면 된다.

기본 구조

class SmartCalculator {
  constructor(model, version) {
    this.model = model;
    this.version = version;
  }

  powerOn() {
    console.log(`${this.model} 전원 켜짐 ✨`);
  }

  add(x, y) {
    return x + y;
  }
}

const myCalc = new SmartCalculator("AI-2023", 2.1);
myCalc.powerOn(); // AI-2023 전원 켜짐 ✨
console.log(myCalc.add(5, 3)); // 8

특징

  • constructor 안에서 초기화 (this.model = ...)
  • 메서드는 클래스 블록 안에 바로 정의 → 내부적으로는 prototype에 올라간다.
  • extends, super로 상속도 깔끔하게 표현 가능
  • TypeScript 쓸 때 클래스 위에 타입만 얹어주면 되니 호환성이 좋다.

장점 요약

  • 문법이 다른 언어(OOP 언어들) 경험자에게도 익숙하다.
  • prototype을 직접 건드릴 일이 줄어든다.
  • 팀 단위로 코드 스타일을 맞추기 좋다.

생성자 함수 - 예전 스타일

클래스가 없던 시절에는 이렇게 썼다.

function ClassicCalculator(model, version) {
  this.model = model;
  this.version = version;
}

ClassicCalculator.prototype.powerOn = function () {
  console.log(`${this.model} 전원 켜짐 ✨`);
};

ClassicCalculator.prototype.add = function (x, y) {
  return x + y;
};

const oldCalc = new ClassicCalculator("Vintage-2000", 1.0);
oldCalc.powerOn(); // Vintage-2000 전원 켜짐 ✨
console.log(oldCalc.add(10, 5)); // 15

특징

  • 함수 본문에서는 주로 필드 초기화만 하고 (this.model = ...)
  • 메서드는 전부 함수명.prototype.메서드 = function () { ... } 꼴로 따로 정의한다.
  • new를 빼먹으면 this가 꼬이거나 전역 오염이 생길 수 있다.
  • TypeScript에서 타입을 얹으려면 생성자 타입, 인스턴스 타입을 따로 정의해줘야 하는 경우가 생긴다.

클래스 vs 생성자 함수 비교

표로 한 번에 정리해보면 대략 이런 느낌이다

항목 ES6 클래스 생성자 함수
문법 직관적, 다른 언어 경험자도 익숙 prototype 등 직접 설정 필요, 장황해지기 쉬움
TypeScript 클래스 위에 타입만 얹으면 끝 생성자/인스턴스 타입을 따로 정의해야 할 때 많음
프로토타입 JS 엔진이 내부에서 처리 직접 함수명.prototype에 메서드 추가
this 관리 new 강제 + 클래스 문법 덕에 덜 헷갈림 new 빼먹으면 전역 오염/에러 위험
상속 표현 extends, super로 깔끔하게 Object.create, call/apply 등 직접 조합
현대적 지원 private 필드, getter/setter 등 지원 문법 레벨 지원 없음, 수동 구현

언제 뭘 쓰면 좋을까? (선택 가이드)

ES6 클래스를 선택하는 경우

  • 새 프로젝트, 모던 프론트엔드/백엔드 코드
  • TypeScript를 쓰는 프로젝트
  • 팀원들이 자바/코틀린/CS 배경이 있어서 클래스 문법이 더 익숙한 경우
  • 상속, 캡슐화, 접근 제어자(private/public 등)를 쓰고 싶을 때

생성자 함수를 유지/사용하는 경우

  • 오래된 코드베이스(레거시)에서 기존 패턴을 그대로 따라가야 할 때
  • IE 같은 구형 브라우저를 직접 대응해야 할 때(트랜스파일링 없이)
  • 라이브러리 내부에서 "옛날 방식" 인터페이스와 호환해야 할 때

이런 특수한 케이스가 아니라면, 굳이 새 코드에서 생성자 함수를 쓰는 일은 거의 없다고 봐도 된다.


this 바인딩 문제도 잠깐 짚고 가기

생성자 함수든 클래스든, this는 항상 조심해야 하는 포인트다.

클래스에서도 이런 상황은 여전히 주의해야 한다.

class ButtonHandler {
  constructor(label) {
    this.label = label;
  }

  handleClick() {
    console.log(`${this.label} 클릭됨`);
  }
}

const handler = new ButtonHandler("저장");

// 이렇게 넘기면 this가 바뀔 수 있다.
button.addEventListener("click", handler.handleClick); // this 문제 가능

이럴 때는

  • 생성자에서 this.handleClick = this.handleClick.bind(this);를 해주거나
  • 아예 클래스 필드 + 화살표 함수 패턴을 쓰기도 한다.
class ButtonHandler {
  constructor(label) {
    this.label = label;
  }

  handleClick = () => {
    console.log(`${this.label} 클릭됨`);
  };
}

핵심은

클래스가 this 문제를 완전히 없애주진 않지만,
생성자 함수 + prototype 조합보다는 훨씬 덜 헷갈리는 구조를 만들어 준다는 것.


내 체크리스트

실제 코드 짤 때는 대충 이렇게 생각하면 편하다.

  • 새 프로젝트 / 모던 환경인가?
    • → 웬만하면 ES6 클래스로 간다.
  • 이미 생성자 함수 + prototype으로 가득한 레거시 코드인가?
    • → 큰 리팩터링 여유가 없다면 일단 기존 스타일을 존중한다.
  • TypeScript를 쓰고 있는가?
    • → 클래스가 타입 선언/추론 측면에서 훨씬 덜 귀찮다.

오늘 내용 한 줄씩 다시 정리

  • ES6 클래스와 생성자 함수는 같은 일을 다른 문법으로 표현하는 느낌이지만,
    • 클래스가 더 읽기 좋고,
    • TypeScript/모던 JS 환경과도 잘 맞는다.
  • 생성자 함수는 레거시/호환성 때문에 여전히 볼 수 있지만,
    • 새 코드에서 굳이 선택할 이유는 많이 줄어든 상태다.
  • 그래서 현실적인 선택은:
    • "특별한 이유가 없으면 클래스",
    • "레거시를 건드릴 수 없을 때만 생성자 함수 유지" 정도로 정리할 수 있다.

결론
요즘 자바스크립트/타입스크립트 코드에서는,
클래스를 기본값으로 두고, 생성자 함수는 레거시 호환용으로만 남겨두는 쪽이
가장 덜 피곤한 선택이다.

저작자표시 변경금지 (새창열림)

'FrontEnd > JavaScript' 카테고리의 다른 글

JavaScript new 연산자  (0) 2025.09.09
JavaScript 합성(Composition) - 상속보다 유연하게 객체 설계하기  (0) 2025.09.09
DOM으로 HTML 다루기 - innerHTML, insertAdjacentHTML, createContextualFragment  (0) 2025.09.09
JavaScript Function.call / apply / bind - this  (0) 2025.09.09
[실무 기록] 폼 실시간 공유 3편 – Yjs Awareness로 상대 커서,선택 상태 보여주기  (0) 2025.09.08
'FrontEnd/JavaScript' 카테고리의 다른 글
  • JavaScript new 연산자
  • JavaScript 합성(Composition) - 상속보다 유연하게 객체 설계하기
  • DOM으로 HTML 다루기 - innerHTML, insertAdjacentHTML, createContextualFragment
  • JavaScript Function.call / apply / bind - this
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    preconnect
    이터러블
    Utility
    yjs
    CRDT
    playwright
    WebSocket
    컬렉션
    고차함수
    주니어
    omit
    javascript
    코테
    CrossOrigin
    타입스크립트
    pick
    배열
    Android
    TypeScript
    Next.js
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
ES6 클래스 vs 생성자 함수 - 요즘 자바스크립트에서 뭘 써야 할까?
상단으로

티스토리툴바