JavaScript

프로토타입(prototype)

whoyoung90 2022. 5. 22. 16:57
반응형

클래스 기반 언어가 상속을 사용한다면

프로토타입 기반 언어는 어떤 객체를 원형(prototype)으로 삼고, 이를 복제(참조)하여 상속과 비슷한 효과를 갖는다.

 

자바스크립트 또한 프로토타입 기반 언어이다!

 

const instance = new Constructor();

어떤 생성자 함수(Constructor)를 new 연산자와 함께 호출하면

Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스(instance)가 생성된다.

 

이 instance에는 __proto__라는 프로퍼티가 "자동 부여"되는데,

이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조한다!

 

즉, 인스턴스는 __proto__를 통해서 생성자함수의 prototype 프로퍼티에 접근할 수 있다.

> 예시

Developer라는 생성자 함수의 prototype에 getName이라는 메서드를 지정했을때

/* 생성자 함수 생성 */
const Developer = function (name) {
  this.name = name;
};
/* 프로토타입에 getName 메서드 지정 */
Developer.prototype.getName = function () {
  return this.name;
};

Developer의 인스턴스는 __proto__를 통해서 getName 프로퍼티에 접근할 수 있다.

const instance = new Developer("Wooyoung");
Developer.prototype === instance.__proto__;  // true

instance.__proto__.getName();                // undefined ⭐️

/* __proto__는 생략가능한 프로퍼티 */
instance.getName();                          // Wooyoung ⭐️⭐️

 

⭐️

undefined가 나오는 이유는 this에 바인딩 대상이 잘못 지정되었기 때문이다.

함수를 메서드로서 호출했는데 this가 instance가 아닌 prototype 객체(instance.__proto__)를 가리키고 있다.

 

instance 내부에는 name 프로퍼티가 존재하지만

prototype 객체(instance.__proto__) 내부에는 name 프로퍼티가 없으므로 undefined를 반환하는 것이다.

(prototype 상에는 name 프로퍼티가 없으므로)

 

c.f) prototype 객체에 직접 name 프로퍼티를 추가하면 정상적으로 출력되기는 한다.

하지만 이때 this가 instance가 아닌

prototype 객체(instance.__proto__)를 바라보고 있으므로 좋은 방법은 아니다..

const instance = new Developer("Wooyoung");

/* prototype 객체에 직접 name 프로퍼티를 추가 */
instance.__proto__.name = "Wooyoung"; // 또는 Developer.prototype.name = "Wooyoung";

instance.__proto__.getName();  // Wooyoung

c.f) 명시적으로 this를 바인딩하는 call, apply 함수를 활용해도 해결은 가능하다!

const instance = new Developer("Wooyoung");

instance.__proto__.getName();               // undefined
instance.__proto__.getName.call(instance);  // Wooyoung

 

⭐️⭐️

__proto__는 생략가능한 프로퍼티이기 때문에

instance.getName()으로 호출 시, 우리가 원하는 this바인딩이 되어 값을 얻을 수 있다.

(instance.__proto__에 있는 getName 메서드를 실행하지만 this는 instance를 바라보는 것!)

 

결국 우리가 실무든 프로젝트든 알게모르게 __proto__가 생략된 채로 사용하고 있었을 것이다🤔

> 정리

new 연산자로 Constructor를 호출하면 instance가 만들어지는데,

이 instance의 생략 가능한 프로퍼티인 __proto__는 Constructor의 prototype을 참조한다!

 

자바스크립트는 함수에 자동으로 prototype 프로퍼티를 생성해 놓는데

new 연산자와 함께 생성자 함수로 사용할 경우,

그로부터 생성된 인스턴스에는 숨겨진 __proto__ 프로퍼티도 자동으로 생성된다고 한다!

 

__proto__ 프로퍼티는 생략가능하도록 구현돼 있기 때문에

생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면

인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있게 된다.

 

 

반응형