프로토타입 Prototype

프로토타입 Prototype

다음 코드를 실행했을 때 prototype과 함께 인스턴스가 생성되는 과정은?

var instance = new Constructor();

어떤 생성자 함수(Constructor)를 new 연산자와 함께 호출하면 Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스가 생성됩니다. 이때 instance에는 __proto__라는 프로퍼티가 자동으로 부여되는데, 이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조합니다. prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장합니다. 그러면 인스턴스에서도 숨겨진 프로퍼티인 __proto__를 통해 이 메서드들에 접근할 수 있게 됩니다.

__proto__의 특성

__proto__ 프로퍼티는 생략 가능하도록 구현돼 있기 때문에 생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있게 됩니다.

constructor 프로퍼티

생성자 함수의 프로퍼티인 prototype 객체 내부와 인스턴스의 __proto__ 객체 내부에는 constructor라는 프로퍼티가 있습니다. 이 프로퍼티는 원래의 생성자 함수(자기 자신)을 참조합니다. 이 constructor 프로퍼티는 인스턴스로부터 그 원형이 무엇인지를 파악할 수 있는 수단입니다.

constructor 접근 방법

var Person = function (name) {
    this.name = name;
};

var p1 = new Person('사람1');
var p1Proto = Object.getPrototypeOf(p1);
var p2 = new Person.prototype.constructor('사람2');
var p3 = new p1Proto.constructor('사람3');
var p4 = new p1.__proto__.constructor('사람4');
var p5 = new p1.constructor('사람');

[p1, p2, p3, p4, p5].forEach(function (p) {
    console.log(p, p instanceof Person);
});

다음 각 줄은 모두 동일한 대상을 가리킵니다.

[Constructor]
[instance].__proto__.constructor
[instance].constructor
Object.getPrototypeOf([instance]).constructor
[Constructor].prototype.constructor

다음 각 줄은 모두 동일한 객체(prototype)에 접근할 수 있습니다.

[Constructor].prototype
[instance].__proto__
[instance]
Object.getPrototypeOf([instance])

프로토타입 체인

prototype 객체는 ‘객체’이기 때문에 기본적으로 모든 객체의 __proto__에는 Object.prototype이 연결됩니다. 어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 프로퍼티가 연쇄적으로 이어진 것을 프로토타입 체인이라 하고, 이 체인을 따라가며 검색하는 것을 프로토타입 체이닝이라고 합니다.

예를들어 생성자 함수는 모두 함수이기 때문에 Function 생성자 함수의 prototype과 연결됩니다. Function 생성자 함수 역시 함수이므로 다시 Function 생성자 함수의 prototype과 연결됩니다. 재귀적으로 반복하는 루트를 따르면 끝없이 찾아갈 수 있습니다.

프로토타입으로 스태틱 멤버와 인스턴스 멤버를 구현하는 방법

생성자 함수를 new 연산자와 함께 호출하면 인스턴스가 생성되고 prototype 객체 내부 요소들이 프로토타입 체이닝에 의해 참조됩니다. 클래스의 상속과 비슷하게 동작한다고 볼 수 있는데 prototype 프로퍼티를 제외한 나머지는 인스턴스에 상속되지 않습니다. 인스턴스에 상속되는지(인스턴스가 참조하는지) 여부에 따라 스태틱 멤버와 인스턴스 멤버로 나뉩니다.