JavaScript

10.2. 프로토타입 : 프로토타입이란, 프로토타입 체인

문정훈 2022. 2. 13. 01:24

1. 프로토타입이란

자바스크립트의 모든 객체는 하나의 "프로토타입"을 가진다. 또한 모든 "프로토타입"은 생성자 함수와 연결되어있다. 

모든 객체라고 하면 막연하니 ( 객체 리터럴,  생성자 함수, 생성자 함수로 생성된 객체 ..) 이정도 범위로 생각하자..

 

모든 객체는 [[Prototype]]이라는 내부 슬롯을 가진다. 이 내부 슬롯에는 프로토타입의 참조가 들어있게 된다.

즉 예를 들어 객체 리터럴로 생성된 객체의 내부 슬롯 [[Prototype]]의 값에는 객체 리터럴로 생성된 객체의 "프로토타입"이 들어있다. 

 

  • 프로토타입
  • prototype
  • __proto__
  • XXX.prototype (ex Object.prototype)

위와 같이 앞으로 이 절을 정리하면서 위와 같은 용어가 메인인데 위 용어들은 엄밀히 다 다른 개념이다 .

그 중 첫 번째인 프로토타입에 대해 우선 설명을 하고 있다. 

프로토타입이란 모든 객체들이 가지는 객체의 부모라고 볼 수 있다. 

 

2. 빌트인 생성자 함수란?

전역 객체가 생성되는 시점에 모든 빌트인 생성자 함수가 생성된다.

빌트인 생성자 함수란 Obejct, Function, String, Array 등등이 있다. 

 

 

 

3. prototype 그리고 __proto__

1) 생성자 함수 객체의 프로토타입 체인

모든 생성자 함수는 prototype이라는 프로퍼티를 가진다. 

생성자 함수 = 빌트인 생성자 함수 + 사용자 정의 (생성자)함수

사용자가 생성자 함수를 정의하는 상상을 해보자.

사용자가 정의한 생성자 함수는 당연히 생성자 함수가 선언된 스코프의(전역 코드라고 하겠다) 평가 과정에서 객체가 생성된다.

이 생성자 함수라는 객체가 생성되면서 prototype이라는 프로터티도 객체의 프로퍼티로 생성될 것이다. 

 

※ 모든 객체의 프로토타입은 해당 객체가 생성되는 시점에 만들어진다. 

 

따라서 생성자 함수 객체가 생성될 때 프로토타입 역시 함께 생성된다. 

그 프로토타입은 생성자 함수 객체에서 __proto__ 프로퍼티를 통해 접근이 가능하다.  (__proto__에 대해서는 차후 설명)

생성자 함수 객체의 프로토타입은 Funciton.prototype이 된다. 

그리고 이 Function.prototype 객체의 대표적인 프로퍼티는 constructor (이것에 대해서도 차후 설명)이 있다. 

Function.prototype의 프로토타입은 최상위 프로토타입인 Object.prototype이 된다. 

 

여기까지 프로토타입 체인에 대한 설명은 사용자가 정의한 생성자 함수 객체에 대한 프로토타입 체인이다. 

이 생성자 함수를 new 연산자를 통해 객체를 생성한다면 생성된 객체의 프로토타입 체인이 존제하게 된다. 

 

 

2) new 연산자로 생성된 객체의 프로토타입 체인

Person이라는 생성자 함수가 있다고 가정해보자. 

이 Person 객체는 prtotype이라는 프로퍼티가 있는데 이는 Person.prototype을 가리킨다. 

하지만 Person 생성자 함수로 new 연산을 통해 객체를 생성하지 않는다면 Person의 prototype 프로퍼티는 아무런 의미가 없어지게 된다. 

 

※ 생성자 함수는 모두 prototype 프로퍼티를 가지며 new 연산을 통해 생성된 객체는 당연히 prototype 프로퍼티를 가진다. 

 

Person을 new 연산자를 통해 생성 시킨 객체를 me라고 가정하겠다.

me라는 객체는 __proto__ 프로퍼티를( Object.prototype 으로부터) 상속 받게 되는데 모든 객체의 __proto__ 프로퍼티는 자신의 프로토타입을 가리키게 된다. 

me의 프로토타입은 Person.prototype이 된다. 

이전에 생성자 함수 Person의 prototype 프로퍼티는 Person.prototype인데 이 객체가 바로 me의 프로토타입이자 me.__proto__ 의 값이 된다. 

Person.prototype은 역시 객체이므로 이 객체의 프로토타입을 가지며 Person.prototype의 프로토타입은 [[Prototype]]의 값인 Object.prototype이 된다. 

 

 

 

4.  constructor 그리고 __proto__

__proto__ 프로퍼티는 최상위 프로토타입인 Object.prototype의 프로퍼티이며 js의 모든 객체는 Object.prototype를 상속받으므로 __proto__를 상속받게 된다.

객체에서 __proto__는 자신의 상위 스코프를 가리키며 이 값이 곳 [[Prototype]]의 값이다. 

 

모든 프로토타입 (XXX.prototype)은 constructor라는 프로퍼티를 가지는데 이 값은 XXX이다. 

예를 들어 Function.prototype이라는 객체는 constructor 프로퍼티를 가지는데 그 값으로 Function이라는 (빌트인)생성자 함수를 가리킨다. 

 

prototype과 contructor의 관계를 다시 정리해보면 Person이라는 사용자 정의 함수있다고 가정해보자.

이 함수가 객체가 될 때 Person의 prototype이 생성되며 Person.prototype객체의 constructor 프로퍼티는 Person을 가리킨다. 즉 프로토타입은 생성자 함수와 더불어 생성되며 prototype, constructor 프로퍼티에 의해 연결된다.

또한 프로토타입과 생성자 함수는 단독으로 존재하지 않으며 언제나 쌍으로 존재하게 된다. 

 

 

 

5. 가상의 생성자 함수

obj = {} //1번 방식
new Object(); //2번 방식

 

위 두 방식 모두 객체를 생성하는 방법이다.

모든 객체는 프로토타입이 존재한다. 

1번 방식에 의해 생성된 객체는 실제론 객체 리터럴로 생성되었지만 객체이므로 프로토타입이 존재하게 된다. 

1번 방식의 프로토타입은 Object.prototype이다. 

 

2번 방식은 Object라는 (빌트인)생성자 함수의 new 연산자로 만들어진 객체이다. 

이는 사용자 정의 함수와 그 형식이 똑같다고 봐도된다. 

Object 생성자 함수는 prototype이라는 프로퍼티를 가지고 있고 new Object() 객체는 prototype을 가지게 된다. 

따라서 new Object()로 생성된 객체의 프로토타입 역시 Object.prototype이 된다. 

 

1번과 2번의 차이점은 2번으로 생성된 객체는 prototype 프로퍼티를 가지며 1번은 prototype 프로퍼티를 가지지 않는다. 다만 1번 방식으로 생성된 객체 역시 프로토타입이 존재해야하기 때문에 마치 Object 생성자 함수로 생성된 것과 같이(실제론 Object 생성자 함수로 생성된 것이 아님) 가상적인 생성자 함수를 가지게 된다. 

Object, Array, String, 사용자 정의 생성자 함수 모두 이와 같은 원리이다.