프로토타입(Prototype)심화

minho·2021년 12월 2일
0

1. prototype, [[Prototype]], constructor


이것은 무엇을 뜻하는 것일까?
Constructor라는 생성자함수가 new를 사용하여 instance를 생성한다.
Constructor옆에 있는 prototype은 프로퍼티이다.
프로퍼티란 객체의 속성을 뜻한다.
즉, Constructor의 속성을 뜻하는 prototype은 [[Prototype]]으로 Constructor 속성의 참조를 전달한다.
([[Prototype]]도 프로퍼티로써 Constructor의 내용을 담게 되는 것이다.)

그결과 Constructor.prototype이랑 instance[[Prototype]]은 같은 객체를 바라본다.

그러나 [[Prototype]]는 접근가능한것이 아니라 정보를 보여주기만 한다.
이것이 무슨말일까?

실제 동작상으로는 prototype은 결국 instance를 가리키게 된다는 것이다.

예를들어 설명해보자

Array를 생성자함수로 만들어 배열[1,2,3]인 instance를 만들었다.
Array에는 from()...prototype까지 여러개의 프로퍼티 들이 있다.
프로퍼티 또한 객체다. 그러므로 prototype안에도 다수의 메서드가 있다.
concat(),pop()등등 배열에 관련된 메서드임을 알 수 있다.
즉, prototype이란 프로퍼티는 [[Prototype]]을 통해서 배열 instance에 메서드들을 전달할 수 있다.


배열 instance를 출력해 보았다.
[[Prototype]]을 보면 Array()의 prototype과 내용이 똑같음을 알 수 있다.


여길보면 prototype의 concstructor는 다시 생성자 함수인 Array()를 가리키는 것을 알 수 있다.
즉, Array.prototype.constructor는 다시 Array()를 가리키는 것을 알 수 있다.

배열.constructor역시 마찬가지로 Array()를 가리킨다.

즉, 배열.constructor를 요청하면 [[Prototype]]의 constructor를 요청하는 것이고, 결국 [[Prototype]]을 가리키게 한것은 Array.prototype이므로 Array.prototype.constructor를 요청한것과 같다.

인스턴스가 객체가 아니면 어떨까?

기본형타입(문자, 숫자등)
객체는 프로퍼티를 만들 수 있지만, 숫자나 문자등 객체가 아닌것들은 프로퍼티를 만들 수 없다.
이럴때는 어떻게 생성자함수의 메서드를 이용할 수 있을까?

숫자 10은 프로퍼티를 만들 수 없으므로 자바스크립트가 임시로 숫자리터럴에 해당하는 Number 생성자 함수의 인스턴스를 만든다.
그 후 Number.prototype에 있는 메서드(여기서는 toFixed())를 숫자 리터럴에 적용한 뒤 원하는 결과 값을 얻은 후 임시로 만든 인스턴스를 제거한다.

참조형타입(함수)
참조형 데이터들은 처음부터 인스턴스이다.

그러므로 기본형타입과 같이 인스턴스를 만들고 지우고 하는 복잡한 과정을 거치지 않아도 된다.


결국 숫자, 문자, 배열, 함수이든 메서드에 접근하고자 할땐 [[Prototype]]과 생성자 함수의 prototype의 연결을 통해 접근하게 된다.
(null과 undefined를 제외한 모든 데이터 타입에는 이와같은 생성자 함수가 존재한다.)

직접 prototype에 접근할 수는 없을까?


[[Prototype]]은 실제로 존제하는 것이 아닌 콘솔에 표시되는 내용일뿐 이를 이용해서 prototype에 직접 접근 할 수는 없다.

그래서 실제로 접근하려면 아래와 같은 두가지 방법이 있다.

__proto__는 공식적이지는 않기 때문에 Object.getPrototypeOf메서드를 사용하는 것이 낫다.

예제를 살펴보자

roy와 royClone들은 모두 Person의 인스턴스가 된다.

  • royClone1의 roy.__proto__는 Person의 property를 가리키고 .constructor가 있으니 결국 생성자 함수 Person을 나타낸다.

  • royClone2의 roy.constructor는 바로 생성자 함수 Person을 가리킨다.

  • royClone3의 Object.getPrototypeOf(roy)는 Persondml property를 가리키고 .constructor가 있으니 결국 생성자 함수 Person을 나타낸다.

  • royClone4의 Person.prototype.constructor는 자기자신을 가리는 것을 알 수 있다.

    2. 메소드 상속 및 동작 원리


    오른쪽을 보면 roy와 jay의 setOlder, getAge메서드 들은 같다.

    그러므로 이렇게 prototype을 이용해 수정할 수 있다.
    오늘쪽 그림과 같이 Person.prototype의 메서드가 되는 것이다.

    이것의 장점을 인스턴스들의 고유한 정보는 다 다르지만 인스턴스들이 모두 똑같이 가지는 정보들은 prototype으로 보내면 된다.
    이는 메모리 용량을 최적화 할 수 있다.

3. 프로토타입 체인(prototype chaining)

프로토 타입 체인을 알기전에 먼저 객체에 대해 정확히 알 필요가 있다.
참조: https://velog.io/@surim014/웹을-움직이는-근육-JavaScript란-무엇인가-part-7-Object-35k01xmdfp

프로퍼티인 prototype역시 객체이다.
그러므로 prototype또한 Object의 인스턴스이며 Object의 prototype에 연결되어 있다.
이 결과 instance는 Object.prototype에 있는 메소드도 사용가능한 것이다.

저 빨간선을 따라 연결되어 있는 것을 프로토타입 체인이라고 부른다.

그러나 이러한 구조 때문에 문제가 생기게 된다.

위와같이 {a:1, b:2}는 객체이다.
그러나 객체의 프로토타입에는 객체 전용 메서드를 정의해 둘 수 없다.
객체의 프로토타입에 있는 메서드는 모든 데이터 타입에 적용되기 때문이다.

예를들어 values()라는 메서드를 사용하면 객체에 대해서는 적용이 가능하다.
그러나 객체가 아닌것들 조차 사용이 가능해져 버린다.
즉, 객체 전용 메서드가 아니게 된다.


그래서 Object.prototype에 메서드를 정의하는 것을 포기하고, 객체 생성자함수에 직접 메서드를 정의할 수 밖에 없다.
그래서 obj.메소드()가 아닌 Object.메소드(obj)방식이 많다.
그 이유가 모두 프로토타입 체인 때문이다.

profile
Live the way you think

0개의 댓글