프로토타입
- 자바스크립트는 프로토타입(prototype)기반 언어
- 클래스 기반 언어 : ‘상속’을 사용
- 프로토타입 기반 언어: 어떤 객체를 원형으로 삼고 이를 복제(참조)하여 상속과 비슷한 효과
- 유명한 프로그래밍 언어의 상당수가 클래스 기반(프로토타입은 꽤 독특한 개념)
6-1 프로토타입의 개념 이해
6-1-1 constructor, prototype, instance
- 프로토타입 도식의 흐름
- var instance = new constructor();
- 어떤 생성자 함수(constructor)를 new 연산자와 함께 호출하면
- Constructor에서 정의된 내용을 바탕으로 새로운 인스턴스(instance)가 생성됨
- 이때 instance에는
__proto__
라는 프로퍼티가 자동으로 부여
- 이 프로퍼티는 Constructor의 prototype이라는 프로퍼티를 참조
- prototype이라는 프로퍼티와
__proto__
라는 프로퍼티의 관계가 프로토타입 개념의 핵심
- prototype과 이를 참조하는
__proto__
는 객체이다.
- prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장
- 인스턴스에서도 숨겨진 프로퍼티인
__proto__
를 통해 메서드들에 접근할 수 있게 됨.
- 학습목적에서의
__proto__
표현 ES5.1명세에서는__proto__
가 아닌 [[prototype]]이라는 명칭으로 정의 되어있다. __proto__
는 사실 브라우저들이 [[prototype]]을 구현한 대상에 지나지 않음 명세에서는 __proto__
로 접근하는 것을 허용하지 않지만 대부분의 브라우저들이 __proto__
에 직접 접근하는 것을 포기하지 않아 ES6에서 이를 호환성 유지 차원에서 정식 인정함. 어디까지나 브라우저에서의 호환성을 고려한 지원일 뿐 권장되는 방식은 아니다. 가급적 실무에서는 __proto__
를 사용하지 않고 Object.getPrototypeOf()/Object.create()를 이용
var Person = function (name) {
this._name = name;
};
Person.prototype.getName = function() {
return this._name;
};
var suzi = new Person('Suzi');
suzi.__proto__.getName();
- instance의
__proto__
가 Constructor의 prototype 프로퍼티를 참조하므로 결국 둘은 같은 객체를 바라봐 에러가 발생하지 않음
- undefined가 나왔다는 것은 이 변수가 호출할 수 있는 함수에 해당한다는 것
- 이 경우는 this에 바인딩된 대상이 잘못 지정되었다.(여기서 this는 suzi.proto )
var suzi = new Person('Suzi', 28);
suzi.getName();
-
__proto__
가 생략 가능한 프로퍼티이다.
- 원래부터 생략 가능하도록 정의되어있음 (걍 설계자 마음이라 이해할 필요없음)
-
__proto__
를 생략하지 않으면 this는 suzi.proto를 가리키지만 생략하면 suzi를 가리킴
- suzi.proto에 있는 메서드인 getName()을 실행하지만 this는 suzi를 바라보게 할 수 있음
-
자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성함.
- new 연산자와 함께 함수를 호출할 경우(생성자 함수로 사용할 경우) 생성된 인스턴스에는 숨겨진 프로퍼티인
__proto__
가 자동으로 생성. 이 프로퍼티는 생성자 함수의 prototype 프로퍼티를 참조.
__proto__
는 생략 가능하게 구현되어 있기 때문에 생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있게 된다.
-
어떤 생성자 함수의 인스턴스는 해당 생성자 함수의 이름을 표기함으로써 해당 함수의 인스턴스임을 표기함.
-
대표적인 내장 생성자 함수Array
- instance를 생성하면 이 인스턴스의
__proto__
은 Array.prototype을 참조하는데, __proto__
가 생략 가능하도록 설계돼 있어 인스턴스가 push, pop, forEach등을 자신의 것처럼 호출 가능
- 단, Array의 prototype 프로퍼티 내부에 있지 않은 from,isArray등의 메서드는 인스턴스가 직접 호출 불가능
- Array 생성자 함수에서 직접 접근해야 실행가능
6-1-2 Constructor 프로퍼티
- 생성자 함수의 프로퍼티인 prototype과 인스턴스
__proto__
객체 내부에는 constructor라는 프로퍼티가 있음.
- 이 프로퍼티는 단어 그대로 원래의 생성자 함수(자기자신)를 참조.
- 인스턴스로부터 그 원형이 무엇인지 알 수 있는 수단(인스턴스와의 관계에서 필요한 정보)
- constructor은 읽기 전용 속성이 부여된 예외적인 경우(기본형 리터럴 변수)를 제외하고 값 변경 가능
- constructor을 변경하더라도 참조하는 대상이 변경될 뿐 이미 만들어진 인스턴스의 원형이 바뀐다거나 데이터 타입이 변하는 것은 아니다.
- 어쩐 인스턴스의 생성자 정보를 알아내기 위해 constructor 프로퍼티에 의존하는 것이 항상 안전한 것은 X
6-2 프로토타입 체인
6-2-1 메서드 오버라이드
- 인스턴스가 prototype에 정의된 프로퍼티나 메서드와 동일한 이름의 프로퍼티 또는 메서드를 가지고 있을 경우
-
메서드 오버라이드가 일어남(메서드 위에 메서드를 덮어씌움)
-
원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹음
-
얹는 형태이기 때문에 원본에 접근할 수 있는 방법도 있음.
-
call이나 aplply를 사용하면 됨
console.log(iu.__proto__.getName.call(iu));
6-2-2 프로토타입 체인
- 기본적으로 모든 객체의
__proto__
에는 Object.prototype이 연결
-
prototype객체도 예외가 아님

- 어떤 데이터의
__proto__
프로퍼티 내부에 다시 __proto__
프로퍼티가 연쇄적으로 이어진 것을 프로토타입 체인(prototype chain)
- 이 체인을 따라가면 검색하는 것을 프로토타입 체이닝(prototype chaining)
- 배열만이 아니라 자바스크립트 데이터는 모두 위 그림과 동일한 형태의 프로토타입 체인 구조
6-2-3 객체 전용 메서드의 예외 사항
- 어떤 생성자 함수이든 prototype은 반드시 객체이기 때문에 Object.prototype이 언제나 프로토타입 체인의 최상단에 존재
- 객체에서만 사용할 메서드는 다른 여느 데이터 타입처럼 프로토타입 객체 안에 정의할 수 없다.
- 객체에서만 사용할 메서드를 Object.prototype 내부에 정의한다면 다른 데이터 타입도 해당 메서드를 사용할 수 있게 되기 때문
- 이런 이유 때문에 객체만을 대상으로 동작하는 객체 전용 메서드들은 부득이 Object에 스태틱 메서드로 부여
- this 사용을 포기하고 대상 인스턴스를 인자로 직접 주입해야 하는 방식으로 구현
- Object.prototype이 참조형 데이터뿐 아니라 기본형 데이터조차
__proto__
에 반복 접근함으로써 도달할 수 있는 최상위 존재이기 때문
- Object.prototype에는 어떤 데이터에서도 활용할 수 있는 범용적인 메서드만 있다.
6-2-4 다중 프로토타입 체인
- 대각선의
__proto__
을 연결해나가기만 하면 무한대로 체인 관계를 이어나갈 수 있음
- 대각선의
__proto__
을 연결하는 방법은 __proto__
가 가리키는 대상, 즉 생성자 함수의 prototype이 연결하고자 하는 상위 생성자 함수의 인스턴스를 바라보게끔 해주면 된다.
- 두 단계 이상의 체인을 지니는 다중 프로토타입 체인도 가능하다 정도로만 알면 됨