🍫 prototype ?? __proto__??

좀 생소하긴 했지만, constructor(생성자) 함수를 만들고 new 키워드를 써서
인스턴트 객체를 만드는 것 까지는 어찌어찌 이해는 됐다.

그런데 도무지 봐도봐도 이해가 잘 가지 않는게 있었으니 그게 바로 지금부터 정리해볼
prototype__proto__ 였다.

지금부터 차근차근 하나씩 사고의 확장을 해나갈 것이다.
javascript에서 함수(function)가 가지는 의미부터 살펴보자.

아래 내용은 생활코딩의 객체 지향 프로그래밍 파트의 자료를 많이 참고했다.
출처 : 생활코딩 (prototype vs proto)

1. 함수(function)도 객체다.

흔히 쓰는 함수는 아래와 같이
name(함수명), parameter(인자), statements(함수 구성문)으로 구성되어 있다.

function name(parameter) { statements }

MDN에 있는 함수 정의를 보면 이런 내용이 있다.

JavaScript에서, 함수는 다른 객체처럼 속성 및 메서드를 가질 수 있기에 일급(first-class) 객체입니다. 다른 객체와 함수를 구별하는 것은 함수는 호출될 수 있다는 것입니다. 간단히 말해, 함수는 Function 객체입니다.
MDN 링크 : 함수

유심히 봐야할 것은 함수는 Function 객체라는 부분이다.
Function 생성자의 정의를 다시 MDN에서 확인해보면, 아래와 같은 내용이 나온다.

Function 생성자는 새 Function 객체를 만듭니다. 이 생성자를 직접 호출하여 동적으로 함수를 생성할 수도 있으나, 보안 문제 및 eval과 유사한(그러나 훨씬 덜 심각한) 성능 문제가 발생할 수 있습니다. 하지만 eval과 달리, Function 생성자는 전역 범위로 한정된 함수만 생성합니다.
MDN 링크 : Function 생성자

우선 여기서 다른건 생각하지 말고 함수가 Function생성자를 통해 만들어진 객체라는 것에만 집중하자.
즉, 객체라는 것은 함수도 속성과 속성값을 가질수 있다는 것이다.

그럼 이제 어떤 속성과 속성값을 가질수 있다는건지 알아보자.

2. 함수(클래스)를 정의하면 두개의 객체가 생긴다?

위에서 했던 클래스 생성자도 함수의 일부다.
아래에 ES5 문법으로 클래스를 임의로 생성해본다.

function Person(name, first, second) {
  this.name = name;
  this.first = first;
  this.second = second;
}

Person.prototype.sum = function(){}

그러면 위 그림과 같이 하나가 아니라 두 개의 객체가 생긴다.
Person이라는 객체와 Person's prototype이라는 객체.
이 두 객체는 서로 연관되어 있다.
이제 어떻게 연관되어 있는지 알아보자.

3. 두 객체는 어떻게 연관될까?

위에서 Person객체와 Person's prototype객체 두 가지가 생겼다.

  • Person객체는 prototype이라는 속성을 가지게 되는데, 그 prototype이 가리키는건 바로 동시에 생성됐던 Person's prototype객체다.
    따라서 Person.prototype 이라고 표현하면 오른쪽의 Person's prototype 객체를 가리키게 되는 것이다.

  • 동시에 Person's prototype 객체는 자신의 소속이 Person이라는 것을 기록해두기 위해,
    constructor라는 속성을 가지고, 이는 왼쪽의 Person 객체를 가리키게 된다.
    따라서 Person.prototype.constructor 라고 표현할 수 있다.

두 객체는 이렇게 서로의 존재를 각각의 속성값을 통해 상호참조하고 있다고 보면 된다.

  • 아까 클래스 생성자 함수를 만들면서 아래와 같이 메소드를 지정했다.
Person.prototype.sum = function(){}

그런데 메소드를 정의하는 표현을 자세히보면 Person.prototype.메소드명 이런식으로 지정하는 것을 확인할 수 있다. 그렇다. Person.prototype은 Person's prototype객체라는 것을 알 수 있고,
sum이라는 메소드는 그림에서 오른쪽에 생성된 Person's prototype 의 속성이 된다.

이제 이렇게 생성된 두 가지의 객체를 통해 수많은 인스턴스 객체를 양산할 수 있게될 준비가 된 것이다.

4. __proto__ 는 도대체 뭐지?

아래와 같이 new 키워드를 통해 인스턴스 객체를 만들어보자.

let kim = new Person('Kim',10,20) 
let lee = new Person('lee',10,10)

자, 이제 그림처럼 kim과 lee 두 가지의 인스턴스 객체가 추가되었다.
우선 생성자 함수의 속성이었던 name, first, second를 3가지를 인자로 전달하여 자신의 속성으로 가져오는 것을 볼 수 있다.
그런데 __proto__라는 듣도보도 못한 괴상한 녀석이 속성으로 생겼다.
__proto__ 는 인스턴스 객체가 생성될 때 자신을 만든 생성자의 prototype 객체
즉, 이 경우에는 Person.prototype객체를 가리키게된다.

5. 찐막

위의 케이스에서 만약 생성된 인스턴스에 name, first, second가 없다면?
(애초에 new를 사용해 인스턴스 객체를 생성할 때 인자로 전달하지 않았다면?)
kim이라는 객체에 name이라는 속성이 빠졌다고 가정해보자.(인자로 전달하지 않음)
이 상태에서 kim.name 을 출력한다면 javascript는 어떻게 동작하는가?

javascript에서는 이때 kim객체의 __proto__ (kim.__proto__)를 찾아가서 name이라는 속성이 있는지 찾고 있다면 출력한다.
kim.__proto__에도 찾는 해당 속성이 없다면??
kim.__proto____proto__를 다시 탐색한다. 이렇게 객체의 __proto__ 를 기준으로 계속 찾게 동작하고 처음 찾는 그 속성을 사용하게 된다.

profile
기획, 개발공부, 그 외 잡다한 여정 기록 (SEMI로)

0개의 댓글

Powered by GraphCDN, the GraphQL CDN