본문 바로가기

Web/Javascript

prototype과 __proto__ 와 constructor

이걸 4개의 포스트에 걸쳐 쓰게 될 줄은 몰랐다. -_-

처음에는 가볍게 시작한 공부였으나..
(이건뭐... 보면볼수록 새로운게 나오니... -_-)

말 그대로 시작은 미미했으나 끝은 창대하리라...

허어...

--------------------------------------------------------------------------------------------------
다시 정리해보자

constructor : 초기화에 사용된 함수(오브젝트)

prototype: 확장하기 위한 오브젝트 (constructor로 초기화된 오브젝트에 대해서)

__proto__ : 프로토타입 오브젝트(프로퍼티가 발견되지 않았을 때에 탐색하러 가는 오브젝트)

이렇게 되는 것인데... (브라우져 마다 틀리다.. -_- firefox 에서는 __proto__ 를 쓰는데 IE에서는 안쓰고
                                prototype 이 대체한다. 괴롭다... 제길)

ECMAscript3 의 오브젝트는 Hash 연상배열이다. 또 각각의 오브젝트는, 프로토 타입 오브젝트를 가진다.
__proto__ 는 Firefox 등에 있는 독자적인 프로퍼티이다.
(firefox 이외에는 잘 모르겠다. 다만 IE 에서는 없다. 대신 이 프로퍼티를 prototype 프로퍼티가 대체한다.)
다음의 코드를 보자

var a = new Object; //또는 var a = { };

이때
a.prototype == null;
a.__proto__ !== a.prototype;
a.__proto__ === Object.prototype;



이렇게 성립이 된다.
이전 포스트에서 마지막에 한것이다.
여기에서 프로토 타입 오브젝트와 prototype 프로퍼티에 속해있는 오브젝트는 별개이다.

a 는 constructor 프로퍼티를 가지고 있지 않은 것에 주의해야한다.
constructor은 프로토 타입 체인으로 가지고 있다.( 이것은 첫번째 포스트에서 언급했다.)

프로토 타입 체인이란..

a = { a:'a'};
b = {};
// 여기에 b.a 는 정의되지 않았다.

b.__proto__ = a;
//위와 같이 하면
alert(b.a); // a 출력
alert(a.a); // a출력


위에서 b.a 로 'a' 의 값이 나올수 있었던것이 프로토 타입 체인이라고 불리는 구조이다.
a 와 b 오브젝트를 생성했을때에는

사용자 삽입 이미지
이렇게 되는것이
b.__proto__ = a; 라고 하면

사용자 삽입 이미지
이렇게 체인을 이어주는것 프로토타립 체인이라고 한다.

1. b의 프로퍼티 a
2. b 의 프로토 타입 오브젝트 의 프로퍼티 a

이처럼 __proto__ 프로퍼티는 각 오브젝트의 프로퍼티를 찾는다.

좀더 보자

a = {a:{}};
b = {b:{}};

b.a !== {};                        // true
b.a === b.__proto__.a;       // true
b.a === a.a;                    //true


위와 같이 b.a와 a.a는 같은 오브젝트를 가리키고 있는 것을 알 수 있다.

__proto__  와 생성자의 관계

 new Constructor 로 초기화 될때

a.prototype = new Object;
a.__proto__ = constructor.prototype;

이런 식으로 내부에서 실행되고 있는거 같다. a.constructor은 프로토 타입 체인에서 가지고 있지 않는다.

Array.prototype.fill = function() {};

등과 Array 생성자의 prototype 프로퍼티의 오브젝트를 확장하는 것으로  Array 생성자로 생성된 모든 오브젝트에 대해 확장을 한것과 같은 효과를 같는다.

var a = [];

a.fill();   // 호출할 수 있다.  하지만

a.hasOwnProperty("fill");    // false 가 된다. 그치만

a.__proto__.hasOwnProperty("fill"); // true

이렇게 된다.


Javascript The Definitive Guide 5th Edition(자바스크립트 완벽가이드)의 p.170 - 171의 오브젝트 관계도 이다.
(내가 말하는 책은 번역서가 아니고 원서이다.. )
 



책에 보면
Rectangle과 PositionedRectangle의 관계는 위의 그림과 같이 되어 있다.
(화살표의 X 표시는 프로토 타입 체인이 연결된다는 표시이다.)

이것의 코드는


function Rectangle(w,h) { }
function PosittionedRectangle(x,y,w,h) {  }

//붉은 화살표가 있는 오브젝트
PositionedRectangle.prototype = new Rectangle();

// 푸른화살표를 만드는 것
PositionedRectangle.prototype.constructor = PositionedRectangle;

Rectangle.prototype 등에는 이름이 없었기 때문에 편의상 _p라는 이름을 붙였다.

예를 들어 r.area 라고 하는 프로퍼티는

1. r.area

2. r.__proto__.area

3. r.__proto__.__proto__.area

이렇게 탐색이 된다.

__proto__ 를 사용하지 않고 어떻게, 붉은 화살표를 연결하고 있는가?

__proto__ 는 ECMA 표준이 아니다. 하지만 지금은 이러한 체인을 만들고 싶은 것이다.
거기서 new Rectangle 로 생성한 오브젝트를 prototype으로 프로토 타입 체인을 형성하고 있다.
책에서 보면 후에 이 오브젝트로부터 불필요한 프로퍼티를 delete 하고 있다.

푸른 화살표만 있으면, 메소드의 탐색은 가능하다.

PositionedRectangle.prototype.constructor = PositionedRectangle;

위의 코드가 없으면  PositionedRectangle 로 만든 오브젝트는 constructor 프로퍼티를 가지지 않기 때문에,
r.constructor === Rectangle; // true

가 되어 버린다.

이것에 관해서는 다음의 포스팅에 prototype 과 constructor 를 이용한 상속에 관해 써볼것이다.