본문 바로가기

디자인패턴

프로토타입 패턴이란?

근데 프로토타입이 뭐죠 ?

사실 공부하기 전에는, 피그마로 만든 디자인을 실행 가능하게 만드는 프로토타입을 생각했다. 약간의 초기모델 수준 ...

여기서의 ProtoType은 자바스크립트의 기본 속성을 말한다 !!

보통 값이 잘 나오는지 확인하려고 콘솔을 찍어보면(콘솔로그말고 디버깅을 사용하자) 이런 화면을 많이 볼 수 있다.

즉 객체 원형을 이용해 만들어진 객체라고 볼 수 있다. 자바스크립트는 프로토타입 기반의 언어라서, 객체지향적으로 프로그래밍할 수 있다 !

 

그래서 프로토타입 패턴이 뭔데?

프로토타입 패턴은 동일 타입의 여러 객체들이 프로퍼티를 공유할 때 사용한다. 즉, 자바스크립트의 기본 속성인 프로토타입을 통해 프로토타입 체인을 사용한다.

 

class Dog {
  constructor(name) {
    this.name = name
  }

  bark() {
    return `Woof!`
  }
}

const dog1 = new Dog('Daisy')
const dog2 = new Dog('Max')
const dog3 = new Dog('Spot')

Dog클래스는 name 프로퍼티를 가지고 있고, Dog 클래스 자체적으로 bark라는 함수를 가지고 있다. ES6 클래스를 사용하면 모든 프로퍼티는 클래스 자체에 선언되므로, Dog의 bark는 자동으로 Dog의 ProtoType에 등록된다.

 

인스턴스 dog1, dog2, dog3는 name이라는 프로퍼티를 가지고, protoType을 가진다. 만약 dog1.bark를 호출하면, 각 인스턴스의 프로토타입을 타고 올라가 Dog 클래스의 bark를 찾고, 호출하게 된다.

(dog1 인스턴스는 bark라는 함수를 내부적으로 가지고 있지 않다!)

console.log(dog1.__proto__)
// constructor: ƒ Dog(name, breed) bark: ƒ bark()

__proto__는 해당 객체의 프로토타입을 확인할 수 있다.

bark가 프로토타입에 저장되어 있는 것을 알 수 있다!

class Dog {
  constructor(name) {
    this.name = name
    this.bark = () => {
    	return `Woof!`
    }
  }
}

const dog1 = new Dog('Daisy')
const dog1 = new Dog('Max')
const dog1 = new Dog('Spot')

만약 이렇게 선언하면 어떻게 될까?

dog1은 name과 bark 프로퍼티를 가지게 된다. 즉 bark 프로퍼티를 공유하는 것이 아닌, 인스턴스 각자 프로퍼티를 소유하게 된다.

dog2도, dog3도 각자 name, bark 프로퍼티를 각각 가지게 된다. 같은 기능을 하는 프로퍼티를 각각 소유하면 메모리의 낭비를 일으키게 된다.

각 인스턴스가 bark를 가지고 있는 것이 아닌, __proto__를 타고 올라가 bark를 찾는다!

__proto__는 프로토타입 객체를 가르킨다. 각 객체는 객체에 없는 프로퍼티에 접근하려고 하면, 프로토타입을 타고 원하는 프로퍼티가 있을 때 까지 타고 올라간다. Prototype 패턴은 객체들이 같은 프로퍼티를 가져야 하는 경우 유용하게 쓰일 수 있다. 중복된 프로퍼티들이 존재하는 객체를 매번 생성하기 보다, Prototype에 프로퍼티를 추가하면 모든 인스턴스들이 Prototype 객체를 활용할 수 있다.

 

인스턴스를 만든 뒤에도, 프로토타입에 프로퍼티를 추가할 수 있다.

Dog.prototype.play = () => console.log("Playing now!");

dog1.play();

이러면 Dog 클래스의 프로토타입에는 bark, play 프로퍼티가 등록된다.

 

또한 프로토타입은 이런 1계층 뿐 아니라, 여러 계층을 가질 수 있다.

즉 ProtoType 객체 또한 proto 속성을 가질 수 있다.

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

  bark() {
    console.log("Woof!");
  }
}

class SuperDog extends Dog {
  constructor(name) {
    super(name);
  }

  fly() {
    console.log(`Flying!`);
  }
}

const dog1 = new SuperDog("Daisy");
dog1.bark();
dog1.fly();

SuperDog는 Dog를 상속받았기 때문에 bark 프로퍼티를 사용할 수 있고, fly 또한 사용할 수 있다.

하지만 bark 프로퍼티를 SuperDog 자체에서 가지고 있지 않다. SuperDog의 proto는 Dog의 ProtoType을 가리키고 있다.

사진으로 보면 다음과 같다.

확실히 체인의 형태죠?

생성한 dog1 인스턴스는 name 프로퍼티를 가진다. fly를 사용하려면 proto를 타고 올라가 SuperDog의 fly를 사용하고, bark를 사용하려면 SuperDog을 살펴보고, 없으니 다시 SuperDog의 proto를 타고 올라가 Dog의 프로퍼티에서 bark를 찾아 사용하는 방식이다.

 

Prototype 체인을 통해 해당 객체에 프로퍼티가 직접 선언되어 있지 않아도 되므로 메서드 중복을 줄일 수 있고 이는 메모리 절약으로 이어진다.

 

프로토타입이 뭔지 애매하게 알고 있었는데, 확실히 알게 된 계기가 된 것 같다.

'디자인패턴' 카테고리의 다른 글

디자인패턴? 그게 뭔데.  (0) 2023.07.27