자바스크립트는 프로토타입(prototype) 기반의 언어로 어떤 객체를 원형으로 삼고 이를 복제함으로써 상속과 비슷한 효과를 얻는다.
모든 객체는 자신을 생성한 객체 원형에 대해 숨겨진 연결을 갖고 자신을 생성하기 위해 사용된 객체원형을 프로토타입이라고 한다.
쉽게말해 어떤 생성자 함수(Constructor)를 new 연산자와 함께 호출하고, Constructor에서 정의된 내용을 바탕으로 새로운 instance가 생성된다.
이때, instance에는 __proto__
(생략가능)가 자동으로 부여되고, 이는 Constructor의 prototype
이라는 프로퍼티를 참조한다.
__proto__
와 prototype
은 프로토타입 개념의 핵심이고, 둘 모두 객체이다.
prototype
객체 내부에는 instance가 사용할 메서드를 저장하고, __proto__
를 통해 이 메서드들에 접근할 수 있게된다.
위 예시는 Person이라는 생성자 함수에 getName이라는 메서드를 지정한 것이다.
생성자 함수를 new 연산자와 함께 호출하여 myName
이라는 instance를 생성했다.
하지만 첫번째 콘솔에서는 undefined
가 출력되었고 "경훈"
이라는 값도 나오지 않고 error
도 발생하지 않았다. 이러한 일이 발생한 이유는 this
에서 찾을 수 있다.
this
는 어떤 함수를 메서드로 호출할 때 메서드 이름 바로 앞의 객체이다.
위 첫번째 콘솔의 예시에서 this
는 myName(instance)
이 아닌 myName.__proto__
으로 인식해서 undefined를 반환한 것이다.
하지만 두번째 콘솔에서는 올바른 값을 출력하였는데 이는 __proto__
를 빼면 myName(instance)
를 인식하기 때문이다.
따라서 여기서 나는 __proto__
가 생략이 가능하다는 점을 기억하고 가야된다.
생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있다.
constructor 프로퍼티는 원래의 생성자 함수(자기자신)을 참조한다. 그리고 constructor는 읽기전용 속성이 부여된 예외적인 경우(number, string, boolean)를 제외하고는 값을 바꿀 수 있다.
그렇다면 이것이 왜 필요한 것일까?
그 이유는 인스턴스로부터 그 원형이 무엇인지를 알 수 있는 수단이 될 수 있기 때문이다.
var arr = [1,2];
Array.prototype.constructor === Array // true
arr.__proto__.constructor === Array // true
arr.constructor === Array // true
var arr2 = new arr.constructor(3,4);
console.log(arr2); [3,4]
(1) 메서드 오버라이드
메서드 위에 메서드를 덮어 씌운 것으로 원본을 제거하고 다른 대상으로 교체하는 것이 아닌 원본이 그대로 있는 상태에서 다른 대상을 그 위에 얹는 것.
(2) 프로토타입 체인
어떤 데이터의 __proto__
프로퍼티 내부에 다시 __proto__
프로퍼티가 연쇄적으로 이어진 것이고 이 체인을 따라가며 검색하는 것을 프로토타입 체이닝(prototype chaining)
이라고 한다.
그리고 자바스크립트의 데이터는 모두 동일한 형태의 포로토타입 체인 구조를 지닌다.