WIL/웹 개발

프로토타입과 클래스

아크리미츠 2024. 12. 11. 16:59

1. 프로토타입(Prototype)

JavaScript의 모든 객체는 프로토타입 기반 상속 방식을 통해 다른 객체의 속성과 메서드를 재사용할 수 있다. 이 상속 구조는 숨겨진 링크인 [[Prototype]]을 통해 이루어진다.

1.1 프로토타입의 원리

  • 객체가 다른 객체로부터 속성과 메서드를 상속받으려면, 숨겨진 링크 [[Prototype]]이 설정된다.
  • 이 링크는 __proto__로 접근 가능하며, 이는 프로토타입 체인을 형성한다.

프로토타입 체인

  • 객체에서 특정 속성이나 메서드를 찾을 때, 해당 객체에 없다면 프로토타입 체인을 따라 상위 객체에서 이를 찾는다.
  • 프로토타입 체인의 끝은 Object.prototype이며, 여기에 기본 메서드들이 정의되어 있다.
const animal = {
  speak() {
    console.log("Animal speaks");
  },
};

const dog = Object.create(animal); // animal을 프로토타입으로 설정
dog.bark = function () {
  console.log("Dog barks");
};

dog.speak(); // "Animal speaks" (프로토타입 체인에서 찾음)
dog.bark();  // "Dog barks" (자신의 속성에서 찾음)

1.2 생성자 함수와 프로토타입

  • 생성자 함수는 객체를 생성하기 위해 사용되며, 모든 생성자 함수는 기본적으로 prototype 속성을 가진다.
  • prototype은 생성된 객체들이 공유하는 속성과 메서드를 정의하는 데 사용된다.
function Animal(name) {
  this.name = name;
}

// 프로토타입에 메서드 추가
Animal.prototype.speak = function () {
  console.log(`${this.name} says hello!`);
};

const cat = new Animal("Cat");
cat.speak(); // Cat says hello!

동작 과정

  1. new Animal("Cat")을 호출하면:
    • 새로운 객체가 생성되고,
    • 해당 객체의 [[Prototype]]Animal.prototype으로 설정된다.
  2. 객체 cat에서 speak 메서드를 호출하면:
    • cat 객체에서 speak를 찾는다.
    • 없으면 Animal.prototype에서 speak를 찾아 호출한다.

2. 클래스(Class)

클래스는 ES6에서 도입된 문법으로, 프로토타입 기반 객체 지향 프로그래밍을 보다 직관적이고 간결하게 사용할 수 있도록 설계되었다. 클래스는 프로토타입을 감싸는 문법적 설탕(syntactic sugar)일 뿐, 실제 동작은 여전히 프로토타입 기반이다.

2.1 클래스의 구조

클래스는 생성자(constructor), 메서드, 정적 메서드, 상속 등으로 구성된다.

class Animal {
  constructor(name) {
    this.name = name; // 초기화
  }

  speak() {
    console.log(`${this.name} says hello!`);
  }

  static generalInfo() {
    console.log("Animals are living beings.");
  }
}

const dog = new Animal("Dog");
dog.speak(); // Dog says hello!

Animal.generalInfo(); // Animals are living beings. (정적 메서드 호출)

2.2 클래스 상속

클래스는 extends 키워드를 사용해 상속을 구현하며, 부모 클래스의 속성과 메서드를 상속받아 사용할 수 있다. 또한, 메서드를 재정의(overriding)할 수도 있다.

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

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }
}

const dog = new Dog("Dog");
dog.speak(); // Dog barks.

3. 프로토타입과 클래스의 차이

구분 프로토타입 클래스
동작 원리 객체를 연결해 상속을 구현 프로토타입 기반 상속을 캡슐화
선언 방식 생성자 함수와 prototype 사용 class 키워드 사용
메서드 정의 prototype 객체에 추가 클래스 내부에 정의
상속 방식 Object.create() 또는 prototype 체인 extends 키워드
가독성 상대적으로 복잡하고 장황 직관적이고 간결

4. 프로토타입과 클래스의 연결

클래스는 내부적으로 프로토타입을 기반으로 동작하기 때문에, class로 작성한 코드도 실제로는 프로토타입 체인을 활용한다.

class Animal {
  speak() {
    console.log("Animal speaks");
  }
}

const animal = new Animal();
console.log(Object.getPrototypeOf(animal) === Animal.prototype); // true

5. 언제 사용해야 할까?

클래스를 사용해야 할 때

  • 코드 가독성을 중시하거나, 팀 협업에서 친숙한 문법을 선호할 경우.
  • 상속 구조를 쉽게 구성하고 유지보수성을 높이고자 할 경우.
  • 현대적인 JavaScript 개발에서 권장됨.

프로토타입을 사용해야 할 때

  • 클래스 이전에 작성된 레거시 코드와 호환해야 할 경우.
  • JavaScript의 동작 원리를 깊이 이해하려고 학습하는 경우.