클래스도 결국 프로토타입 기반으로 동작합니다.


ES6(ECMAScript 2015)는 2015년에 정식으로 도입되었습니다. 이때 let, const , class, arrow function, 백틱, Promise 등의 다양한 문법들이 추가되었습니다.

다양한 문법들 중 클래스라는 문법이 눈에 띕니다. 원래 자바스크립트는 프로토타입 객체를 통해 상속하는 방식으로 클래스의 상속 개념과 비슷한 방식으로 동작해왔습니다. 그렇다면 클래스가 도입된 이후로는 프로토타입과는 어떤 관계를 이루고 있을까요?

결국 근본이 변하진 않았다

클래스라는, 많은 개발자들에게 친숙한 개념이 도입되긴 했으나, 결국 자바스크립트만의 프로토타입 개념이 사라진 것은 아닙니다. 그 말인 즉슨, 클래스는 내부적으로는 프로토타입과 연관되어 구현되어 있다는 소리겠죠?

클래스와 프로토타입의 관계

소스코드로 설명해보겠습니다

결국 내부적으로는 프로토타입을 사용

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

  sayHello() {
    console.log(`Hello, I'm ${this.name}`);
  }
}

const person1 = new Person("Alice");

console.log(person1.__proto__ === Person.prototype); // ✅ true
console.log(Person.prototype.sayHello === person1.sayHello); // ✅ true

윗 코드를 보면, 결국 프로토타입을 기반으로 동작하기에, 클래스를 이용해 객체를 생성하더라도 여전히 프로토타입 체인을 통해 메서드를 상속받고 있습니다. sayHello()는 정확히는 Person.prototype 객체에 저장되어있다고 보는 게 맞죠.

클래스 = 생성자 함수

// 1️⃣ class 문법 사용
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, I'm ${this.name}`);
  }
}

// 2️⃣ 기존의 프로토타입 기반 방식
function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function () {
  console.log(`Hello, I'm ${this.name}`);
};

클래스도 결국에는 생성자 함수와 동일한 방식으로 변환되어 실행되기에, 클래스라는 문법이 유저에게는 직관적으로 보일지는 몰라도 여전히 프로토타입 기반의 객체 생성 방식을 유지하고 있음을 알 수 있습니다.

생성자 함수 vs 클래스

클래스가 결국 생성자 함수로 변환되어 실행된다면, 보통이라면 인스턴스를 생성해야 메서드를 사용할 수 있을텐데, 그럼 프로토타입과는 어떻게 관련되어있는 걸까요?

  1. 생성자 함수 내에서 정의한 메서드(인스턴스의 메서드)

    function Person(name) {
      this.name = name;
      this.sayHello = function () {
        console.log(`Hello, my name is ${this.name}`);
      };
    }
    
    const person1 = new Person("Alice");
    const person2 = new Person("Bob");
    
    console.log(person1.sayHello === person2.sayHello); // ❌ false (각 인스턴스마다 새로운 함수가 생성됨)
    
  2. 프로토타입을 사용한 메서드(공유 메서드)

    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.sayHello = function () {
      console.log(`Hello, my name is ${this.name}`);
    };
    
    const person1 = new Person("Alice");
    const person2 = new Person("Bob");
    
    console.log(person1.sayHello === person2.sayHello); // ✅ true (같은 메서드를 공유)
    
  3. 클래스 내 메서드(프로토타입 메서드)

    핵심은 이 부분입니다. 클래스 내에 구현된 일반 메서드는, 인스턴스를 생성해야만 메서드를 사용 가능한 게 아니라, 클래스명.prototype 형태로도 동일 메서드를 사용할 수 있게 됩니다.

    class Person {
      constructor(name) {
        this.name = name;
      }
    
      sayHello() {
        console.log(`Hello, my name is ${this.name}`);
      }
    }
    
    const person1 = new Person("Alice");
    const person2 = new Person("Bob");
    
    console.log(person1.sayHello === person2.sayHello); // ✅ true
    console.log(person1.sayHello === Person.prototype.sayHello); // ✅ true 
    

그렇다면, 상속은?