자바스크립트는 프로토타입 기반의 언어다.
클래스 기반 언어에서는 '상속'을 사용하지만 프로토타입 기반 언어에서는 어떤 객체를 원형(prototype)으로 삼고 이를 복제(참조)한다. 결국 '상속'과 비슷한 개념이라고 볼 수 있다.
__proto__
라는 프로퍼티가 자동 부여된다__proto__
역시 객체다__proto__
를 통해 prototype에 저장되어있는 메서드에 접근한다__proto__
를 읽을 때는 'dunder proto'라고 발음하면 된다. dunder는 double underscore의 줄임말이다예제를 통해 살펴보자
var Person = function (name) {
this._name = name;
};
Person.prototype.getName = function() {
return this._name;
};
var sia = new Person('Sia');
sia.__proto__.getName(); // undefined ----(1)
Person.prototype === sia.__proto__ // true -----(2)
(1) 메서드 결과로 왜 undefined
가 나왔을까? 에러가 뜨지 않았다는 것은 곧 이 변수가 '호출할 수 있는 함수'라는 뜻이다. 만약 실행할 수 없는 함수라면 TypeError가 발생했을 것이다. 따라서 getName
이 함수라는 것이 입증됐다.
일단 함수라는 것은 확인했고,
그렇다면 왜 undefined
가 나온건지 살펴보자. 문제는 this에 바인딩된 대상이 잘못되었기 때문이다.
어떤 함수를 '메서드로서' 호출할 때는 메서드명 바로 앞의 객체가 곧 this
가 된다. 즉 sia.__proto__.getName()
에서 getName
함수 내부에서의 this
는 sia
가 아니라 sia.__proto__
라는 객체라는 것이다. 이 객체 내부에 name 프로퍼티가 없으므로 찾고자하는 식별자가 정의되어있지 않기 때문에 undefined
를 뱉어낸 것이다.
만약 위 예제가 아래와 같이 바뀐다면 ?
var sia = new Person('Sia');
sia.__proto__._name = 'SIA__proto__'
sia.__proto__.getName(); // SIA__proto__
결국 관건은 this
였다!
this
를 인스턴스로 해서 __proto__
없이 인스턴스에서 곧바로 메서드를 쓰면 좋을 것 같다.
var sia = new Person('SIA', 03);
sia.getName(); // SIA
var moa = new Person('MOA', 04);
moa.getName(); // MOA
어떻게 __proto__
없이 바로 되지?
그 이유는 바로 __proto__
가 생략 가능한 프로퍼티이기 때문이다. 원래부터 생략 가능하도록 정의되어있었고 이 정의를 바탕으로 자바스크립트의 전체 구조가 구성된 것이다.
sia.__proto__.getName
-> sia(.__proto__).getName
-> sia.getName
위 예제에서 __proto__
를 생략하지않고 그대로 쓰면 this
는 sia.__proto__
를 가리키지만, 이를 생략하면 sia
를 가리킨다.
생성자 함수의 프로퍼티인 prototype 객체 내부에 constructor라는 프로퍼티가 있다. 이 프로퍼티는 원래의 생성자 함수(자기 자신)을 참조한다. 이 프로퍼티는 인스턴스와의 관계에서 꼭 필요한 정보다.
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); // - A
console.log(arr2); // [3, 4]
__proto__
가 생성자 함수의 prototype 프로퍼티를 참조하며 __proto__
가 생략 가능해졌다. __proto__
덕분!직각삼각형의 대각선 방향, 즉 __proto__
방향을 계속 찾아가면 최종적으로는 Object.prototype
에 이르게 됨.
이런 식으로 __proto__
안에 다시 __proto__
를 찾아가는 과정을 프로토타입 체이닝이라고 함.
프로토타입 체이닝을 통해 각 프로토타입 메서드를 자신의 것처럼 호출할 수 있음.
proto를 dunder proto 라고 읽는군요 ㅋㅋ
프로토타입과 클래스는 실제 업무할 때 언제 쓰는건지 항상 궁금한데 아직 답변을 못찾았어요.. use cases도 같이 소개해주세요!