"클래스는 프로토타입의 문법적 설탕인가?"
[모던 자바스크립트] 책의 '클래스' 파트의 첫 제목은 이렇습니다.
클래스는 사실상 JavaScript에서 함수와 프로토타입 기반 패턴을 사용할 때 생기는 번거로움을 줄이기 위한 편의 문법입니다. 기존의 프로토타입 기반 패턴을 더 클래스 기반 패턴처럼 사용할 수 있도록 하는 것이라고 볼 수 있습니다. 둘이 비슷한 기능을 가진듯 하지만 동일하게 동작하지 않기 때문에 둘을 함께 살펴보면 좋을 것 같아 함께 정리해보려고 합니다. 그럼 프로토타입과 클래스에 대해 알아봅시다! 🚀
JavaScript에서 모든 객체는 부모 객체로부터 상속을 받는데, 이 부모 객체를 프로토타입(Prototype)이라고 합니다. 객체의 프로토타입은 해당 객체를 생성하기 위해 사용된 원본 객체로 생각할 수 있습니다.
JavaScript는 프로토타입 체인을 통해 객체 간 상속을 구현합니다. 객체는 자신의 프로토타입을 가리키는 __proto__라는 내부 프로퍼티를 가지고 있습니다. 이를 통해 자식 객체가 부모 객체의 프로퍼티와 메서드에 접근할 수 있습니다.
// 예시 객체 생성
let childObj = {};
let parentObj = { x: 10 };
// 프로토타입 설정
childObj.__proto__ = parentObj;
// childObj는 부모 객체의 프로퍼티에 접근 가능
console.log(childObj.x); // 출력: 10
객체 지향 프로그래밍에서 생성자 함수는 객체를 생성하기 위한 템플릿 역할을 합니다. 생성자 함수를 사용할 때, 해당 함수의 prototype 프로퍼티에 정의된 메서드나 프로퍼티는 생성된 객체의 프로토타입이 됩니다.
// 생성자 함수 정의
function Person(name) {
this.name = name;
}
// 프로토타입에 메서드 추가
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}`);
};
// 객체 생성
let person1 = new Person('John');
// 프로토타입 메서드 호출
person1.sayHello(); // 출력: Hello, I'm John
Object.create() 메서드를 사용하면 지정된 프로토타입 객체를 가지는 새로운 객체를 생성할 수 있습니다.
// 프로토타입 객체 생성
let parentObj = { x: 10 };
// 새로운 객체 생성 및 프로토타입 설정
let childObj = Object.create(parentObj);
// childObj는 부모 객체의 프로퍼티에 접근 가능
console.log(childObj.x); // 출력: 10
hasOwnProperty() 메서드는 객체 자체에 특정 프로퍼티가 있는지를 확인합니다. 프로토타입 체인 상에서 상위 단계에 있는 프로퍼티는 체크하지 않습니다.
let parentObj = { x: 10 };
let childObj = Object.create(parentObj);
console.log(childObj.hasOwnProperty('x')); // 출력: false
클래스는 객체 지향 프로그래밍에서 객체를 생성하기 위한 템플릿 역할을 하는 구조입니다. 클래스는 class 키워드를 사용합니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, I'm ${this.name}`);
}
}
constructor 메서드는 클래스에서 객체를 생성할 때 호출되는 특별한 메서드입니다. 이 메서드 내에서 객체의 초기화를 수행합니다.
클래스 내에서 메서드는 일반 함수처럼 정의됩니다. 메서드는 해당 클래스의 인스턴스에서 호출될 수 있는 함수입니다.
클래스를 기반으로 객체(인스턴스)를 생성할 때는 new 키워드를 사용합니다.
let person1 = new Person('John', 25);
person1.sayHello(); // 출력: Hello, I'm John
클래스를 통해 상속을 구현할 수 있습니다. extends 키워드를 사용하여 부모 클래스를 상속받을 수 있습니다.
class Student extends Person {
constructor(name, age, grade) {
super(name, age); // 부모 클래스의 생성자 호출
this.grade = grade;
}
study() {
console.log(`${this.name} is studying.`);
}
}
let student1 = new Student('Alice', 20, 'A');
student1.sayHello(); // 출력: Hello, I'm Alice
student1.study(); // 출력: Alice is studying.
static 키워드를 사용하면 클래스의 인스턴스를 생성하지 않고도 직접 클래스에서 호출할 수 있는 정적 메서드를 정의할 수 있습니다.
class Calculator {
static add(x, y) {
return x + y;
}
}
console.log(Calculator.add(5, 3)); // 출력: 8
JavaScript에서는 기본적으로 모든 멤버가 public이지만, 클래스 내의 멤버를 private 또는 protected로 지정하는 기능은 없습니다. 하지만 최신 JavaScript 환경에서는 #을 사용하여 클래스 내에서만 접근 가능한 private 멤버를 정의할 수 있게 되었습니다.
class Example {
#privateField = 10;
getPrivateField() {
return this.#privateField;
}
}
💡 이렇듯 클래스는 JavaScript에서 객체 지향 프로그래밍을 더 편리하게 하기 위해 도입된 새로운 문법 구조입니다. 기존에는 프로토타입을 기반으로 객체를 생성하고 상속을 구현하는 것이 번거로웠는데, 클래스는 이러한 작업들을 더 간결하게 할 수 있게 해줍니다. 그래서 클래스는 단순히 문법적인 편의뿐만 아니라, 객체 지향 프로그래밍을 위한 새로운 접근 방식을 제시하는 도구로 볼 수 있을 것 같습니다.