JavaScript에서 Class는 Function이다.
자바스크립트의 클래스는 내부적으로 함수로 구현되어 있습니다. Person 클래스를 통해 어떤 의미인 지 이해해보도록 하겠습니다. Person 클래스는 name 필드와 생성자, sayHello 메소드를 갖고 있습니다. 먼저, 생성자 함수를 살펴보겠습니다.
class Person {
name: string;
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
}
생성자는 자바스크립트 내부적으로 아래와 같은 함수의 형태를 가집니다. this는 새로 생성되는 객체를 가리키고, constructor 내부의 코드가 여기서 실행됩니다. name이라는 매개 변수를 받아서 새로 생성될 객체의 필드(name)에 해당 값을 저장하고, 암묵적으로 return this가 발생하게 되면, 생성자 함수가 종료됩니다.
function Person(name) {
this.name = name;
// return this; 이 부분
}
sayHello 메서드를 JavaScript로 변환하면 아래와 같은 코드가 됩니다. 그 이유는 JavaScript는 프로토타입 기반 언어로서, 클래스의 메서드를 각 인스턴스에 직접 추가하는 대신 prototype에 추가하는 것이 메모리 효율성과 상속 구현을 위한 핵심적인 방식이기 때문입니다.
예를 들어, Person 클래스의 sayHello 메서드를 각 인스턴스에 직접 추가한다면, Person 클래스의 인스턴스를 1000개 만들 때 sayHello 메서드도 1000개가 생성됩니다. 이는 엄청난 메모리 낭비가 됩니다. sayHello 메소드를 Person.prototype에 한 번만 추가하고, 모든 Person 인스턴스는 이 하나의 메서드를 공유하여 사용합니다. 인스턴스에서 sayHello를 호출하면, 먼저 인스턴스 자체에서 이 메서드를 찾고, 없으면 prototype으로 올라가서 찾습니다. 이를 `프로토타입 체인`이라고 합니다.(프로토타입 체인은 객체가 속성이나 메소드를 찾을 때, 탐색하는 연결된 객체들의 경로를 말합니다.)
Person.prototype.sayHello = function () {
console.log(`Hello, I'm ${this.name}`);
};
인스턴스 생성 후 sayHell() 실행 과정
- new Person()으로 인스턴스를 생성하면, 이 인스턴스의 proto는 자동으로 Person.prototype을 가리킵니다.
- person.sayHello()를 호출하면, JavaScript 엔진은 먼저 person 객체 자체에서 sayHello 메서드를 찾습니다.
- 찾지 못하면 person.proto(즉, Person.prototype)에서 찾습니다.
- 여기서 sayHello 메서드를 찾아 실행합니다.
정말일까?
놀랍게도 정말입니다. 클래스는 함수입니다. 이것은 JavaScript의 역사적 배경과 설계 철학에 깊이 연관되어 있다고 합니다. JavaScript는 1995년 Brendan Eich에 의해 단 10일 만에 만들어졌습니다. 당시 Java가 인기 있었기에, JavaScript도 객체 지향 프로그래밍을 지원해야 했습니다. 하지만 시간 제약과 브라우저의 경량화 요구사항으로 인해, Java처럼 완전한 클래스 기반 시스템을 구현하기는 어려웠고, 프로토타입 기반 언어로 설계하게 되었다고 합니다. 기존에는 class 문법이 존재하지 않았습니다. 하지만, 기존의 프로토타입 기반 상속이 직관적이지 않고, 더 명확한 객체 지향 프로그래밍 패턴을 제공하기 위해 ES6에서 도입되었다고 합니다. 결론적으로, JavaScript가 클래스를 함수로 구현한 것은 단순한 설계 선택이 아니라, 언어의 특성과 요구사항, 그리고 실용적인 이점들을 고려한 결과였습니다.
class Person {
name: string;
constructor(name:string) {
this.name = name;
}
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
}
console.log(typeof Person); // function
console.log(Person === Person.prototype.constructor); // true
참고 자료