6. 프로토타입

코어 자바스크립트 06_프로토타입


  • 자바스크립트는 프로토타입 기반 언어.
  • 프로토타입 기반 언어는 어떤 객체를 원형(prototype)으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 얻음.
    cf) 클래스 기반 언어 : '상속'을 사용.

1. 프로토타입의 개념 이해

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

__proto__는 생략 가능한 프로퍼티

=> 인스턴스에서 __proto__ 없이 바로 메서드를 쓸 수 있다. (this가 인스턴스가 되도록!)
=> Constructor.prototype의 메서드들을 자신의 메서드인 것처럼 호출할 수 있다.

var Person = function(name) {
	this._name = name;
};
Person.prototype.getname = function() {
	return this._name
};

var suzi = new Person('Suzi');
suzi.__proto__.getName()            //undefined
suzi.__proto__.getName
-> suzi(.__proto__).getName         //'.__proto__' 생략 가능
-> suzi.getName                     // getName 함수의 this는 'suzi'

정리

  • 자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성해놓음.
  • 해당 함수를 생성자 함수로 사용할 경우(= new 연산자와 함께 함수를 호출할 경우), 그로부터 생성된 인스턴스에는 숨겨진 프로퍼티인 __proto__가 자동으로 생성.
  • 이 프로퍼티는 생략 가능.
    => 생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근 가능.

1-2. constructor 프로퍼티

  • 생성자 함수의 프로퍼티인 prototype 객체 내부에는 constructor 프로퍼티 존재.

  • 인스턴스의 __proto__ 객체 내부에도 마찬가지.

  • constructor 프로퍼티는 생성자 함수(자기 자신)을 참조.

  • constructor 프로퍼티는 읽기 전용 속성이 부여된 예외적인 경우(기본형 리터럴 변수 - number, string, boolean)를 제외하고는 값을 바꿀 수 있다.
    => 어떤 인스턴스의 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는 게 항상 안전하지는 않음.

다양한 constructor 접근 방법

  • 모두 동일한 대상(생성자 함수, constructor)을 가리킴.
[Constructor]
[instance].__proto__.constructor
[instance].constructor
Object.getPrototypeOf([instance]).constructor
[Construntor].prototype.constructor

2. 프로토타입 체인

2-1. 메서드 오버라이드

  • 인스턴스가 생성자 함수의 prototype에 있는 것과 동일한 이름의 프로퍼티 또는 메소드를 가지고 있는 경우
    => 자바스크립트 엔진은 먼저 자신의 프로퍼티를 검색하고, 없으면 그 다음으로 가까운 대상인 __proto__를 검색. (가까운 순으로)
  • 메서드 위에 메서드를 덮어씌웠다. (원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹음)

메서드 오버라이딩이 이뤄져 있는 상황에서 prototype에 있는 메서드에 접근하는 방법

: call 또는 apply로 해결.

var Person = fucntion(name) {
	this.name = name;
};
Person.prototype.getName = function() {
	return this.name;
};

var iu = new Person('지금');
iu.getName = function () {
	return '바로' + this.name;
};
console.log(iu.getName());        //바로 지금

console.log(iu.__proto__.getName.call(iu));    //지금

2-2. 프로토타입 체인

  • prototype 객체는 객체(Object).
    => 모든 객체의 __proto__에는 Object.prototype이 연결.

Array.prototype : '객체'이므로 Object의 인스턴스다. => Object.prototype을 참조.

  • 프로토타입 체이닝 : __proto__ 안에 다시 __proto__를 찾아가는 과정.

  • 어떤 메서드를 호출하면 자바스크립트 엔진은 데이터 자신의 프로퍼티들을 검색해서 해당 메서드가 있으면 그 메서드를 실행하고, 없으면 __proto__를 검색해서 있으면 실행하고, 없으면 다시 __proto__를 검색해서 실행.

  • __proto__ 방향을 계속 찾아가다 보면 최종적으로는 Objsct.prototype에 당도하게 된다.
    => 자바스크립트 데이터는 모두 우측 꼭짓점에 무조건 Object.prototype이 있는 프로토타입 체인 구조를 지닌다.


2-3. 객체 전용 메서드의 예외사항

  • Object.prototype에는 다른 데이터 타입도 접근 가능하기 때문에 객체에서만 사용할 메서드는 Object.prototype이 아닌 Object에 스태틱 메서드로 부여.

  • Object.prototype에는 어떤 데이터에서도 활용할 수 있는 범용적인 메서드들만 있다. (toString, hasOwnProperty, isPrototypeOf 등)

  • Object.create(null) : __proto__가 없는 객체를 생성. (내장 메서드 및 프로퍼티들이 제거됨으로써 기본 기능에 제약이 생긴 대신, 객체 자체의 무게가 가벼워짐으로써 성능상 이점을 가짐)


2-4. 다중 프로토타입 체인

  • 대각선의 __proto__를 연결하는 방법 : 생성자함수의 prototype(=__proto__가 가리키는 대상)이, 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보게끔 해주면 된다.
  • 프로토타입 체이닝은 반드시 2단계로만 이뤄지는 것이 아니라 무한대의 단계를 생성할 수 있다.

좋은 웹페이지 즐겨찾기