JS-왜 프로토타입을 사용하나

topics 200-프론트개발
types 이론
tags #javascript #prototype #oop
references medium.com/@limsungmook/%EC%9E%90%EB%...

왜 prototype을 사용하는가?

자바스크립트는 왜 클래스 기반이 아니라 프로토타입 기반 언어로 만들어졌을까?

프로토타입의 실용적인 장점

1. 메모리 효율성

클래스로 객체를 만들 때, 메서드를 매번 복사하지 않고 prototype에 한 번만 정의하면 모든 인스턴스가 공유한다.

// 메모리 비효율적
function Dog(name) {
  this.name = name;
  this.bark = function() {  // 인스턴스마다 복사됨
    console.log(this.name + ' barks!');
  };
}

// 메모리 효율적
function Dog(name) {
  this.name = name;
}
Dog.prototype.bark = function() {  // 한 번만 정의, 모두 공유
  console.log(this.name + ' barks!');
};

const dog1 = new Dog('멍멍이');
const dog2 = new Dog('바둑이');

console.log(dog1.bark === dog2.bark);  // true - 같은 함수 참조

2. 동적 확장 가능

프로토타입은 런타임에 동적으로 변경할 수 있다. 이미 생성된 인스턴스에도 영향을 준다.

function Cat(name) {
  this.name = name;
}

const cat1 = new Cat('나비');

// 나중에 메서드 추가 가능
Cat.prototype.meow = function() {
  console.log(this.name + ' meows!');
};

cat1.meow();  // 이미 생성된 인스턴스에서도 사용 가능!

이건 클래스 기반 언어에서는 불가능하다. Java나 C++에서는 클래스 정의를 바꾸려면 재컴파일해야 한다.

3. 유연한 상속

프로토타입 체인을 이용하면 다중 상속처럼 동작하는 패턴을 만들 수 있다. (믹스인 패턴 참고)

const canEat = {
  eat: function(food) {
    console.log(`Eating ${food}`);
  }
};

const canWalk = {
  walk: function() {
    console.log('Walking...');
  }
};

function Person(name) {
  this.name = name;
}

// 여러 기능을 조합
Object.assign(Person.prototype, canEat, canWalk);

const person = new Person('민지');
person.eat('pizza');  // Eating pizza
person.walk();        // Walking...

철학적 배경

왜 Brendan Eich는 프로토타입 방식을 선택했을까?

Class 기반 (플라톤)

눈앞에 실제로, 구체적으로 존재하는 사물이 있다면 반드시 그것의 본질이 존재한다

개념을 추상화하여서 정의하고, 인스턴스화하여 구체적으로 정의한다.

But, 현실에는 모든 것을 추상화하여 분류할 수 없는 경우가 존재한다.

Prototype 기반 (비트겐슈타인)

공유 속성의 관점에서 정의하기 어려운 개념이 있다.
세계에 미리 내재되어서 대상과 언어를 완전히 규정하는 어떤 언어란 존재하지 않는다.
표현은 삶의 흐름 속에서만 의미를 갖는다.

맥락이 중요하다. → this 동적할당, 실행 컨텍스트...

→ 대상을 분류할 때 모집단에서 가장 유사성 높은 것 (가장 다른 것들과 비슷한 점이 많은 것)을 기준으로 잡는다. → prototype

언제 프로토타입을 직접 쓰나

요즘은 ES6 class 문법을 쓰지만, 내부적으로는 프로토타입으로 동작한다. (JS-클래스 참고)

직접 프로토타입을 쓰는 경우:

  1. polyfill 만들 때 - 내장 객체에 메서드 추가
  2. 라이브러리/프레임워크 개발 - 성능 최적화가 중요할 때
  3. 동적으로 메서드 추가/제거 - 런타임에 객체 동작을 변경해야 할 때
// polyfill 예시
if (!Array.prototype.includes) {
  Array.prototype.includes = function(searchElement) {
    // 구현...
  };
}

주의: 내장 객체의 프로토타입을 함부로 수정하면 다른 코드와 충돌할 수 있다. 꼭 필요한 경우(polyfill)만 사용하자.

프로토타입 vs 클래스

프로토타입 클래스
문법 Dog.prototype.bark = ... class Dog { bark() {...} }
가독성 낮음 높음
동적 수정 쉬움 어려움
성능 근소하게 빠름 근소하게 느림
사용 시기 라이브러리 개발, polyfill 일반적인 애플리케이션 개발

결론: 일반적인 개발에서는 class 문법을 쓰자. 하지만 프로토타입의 동작 원리를 이해해야 디버깅이나 최적화할 때 도움이 된다.


관련 문서

  • JS-prototype - 프로토타입 상세 설명
  • JS-클래스 - class 문법과 프로토타입의 관계
  • JS-this - this 바인딩과 실행 컨텍스트
  • JS-믹스인 - 믹스인 패턴으로 다중 상속처럼 사용하기