프로토타입은 해당 객체의 원형이 되는 객체로, 다른 객체에서 상속된 속성 및 메서드를 포함할 수 있습니다.
prototype based language라 불릴만큼
prototype은 자바스크립트를 지탱하는 기반
자바스크립트 동작 원리를 이해하기 위해서 prototype의 개념을 잘 이해하고 있어야함
OOP 프로그래밍의 상속화를 구현하는데 사용
자바스크립트 모든 객체는 자신의 부모 역할을 하는 객체와 연결돼있다. 이것은 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티, 메소드를 상속받아 사용할 수 있다.
이 때, 부모 객체를 Prototype Object(프로토타입 객체) 또는 Prototype(프로토타입)이라고 한다.
ECMAScript spec에서 자바스크립트 모든 객체는 [[Prototype]]이라는 인터널 슬롯(interner slot)을 가짐.
[[Prototype]] 의 값은 Prototype Object(프로토타입 객체)이며 __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf()가 호출돼 Prototype Object(프로토타입 객체)를 반환.
객체를 생성할 때 프로토타입은 결정되며, 결정된 프로토타입 객체는 다른 객체로 변경할 수 있다. 부모 객체은 프로토타입을 동적으로 변경 할 수 있다는 것.
모든 객체는 자신의 프로토타입 객체를 가리키는 [[Prototype]] 인터널 슬롯을 가짐.
함수도 객체이므로 [[Prototype]]인터널 슬롯을 가진다. 함수 객체는 일반 객체와는 달리 prototype 프로퍼티도 있음.
prototype프로퍼티와 [[Prototype]]은 다르므로 주의
모든 객체는 자신의 prototype으로부터 constructor 속성을 상속
즉, 자신을 생성한 객체를 가리킴
function Carrot(weight){
this.weight = weight;
}
const carrot1 = new Carrot(1);
//carrot1을 생성한 객체는 Carrot이다.
carrot1.constructor == Carrot; //true
//carrot1의 Prototype Object(프르토타입 객체)는 Carrot의 prototype 프로퍼티
carrot1.__proto__ == Object.getPrototypeOf(carrot1) == Carrot.prototype; //true
//함수 객체 Carrot의 contructor, 즉 Carrot을 생성한 객체는 Function이다
Carrot.constructor == Function //true
//그리고 함수 객체 Carrot의 Prototype Object(프로토타입 객체)는 Function.prototype이다.
Object.getPrototypeOf(Carrot) == Function.prototype; //true
__proto__ 는 ES6(ECMAScript2015) 이후 Object.getPropertyOf()로 사용하는 것을 권장
prototype 대신 Class, extends 를 사용하는 것 권장
객체의 프로퍼티나 메소드에 접근할 때 해당 객체에서 찾을 수 없으면, 내부적으로 Object.getPrototypeOf()를 이용해 부모를 찾아가서 가져오고 없으면 또 부모로가고 찾을때까지 가다가 Object.getPrototypeOf()의 결과가 null일 때 까지 찾지 못하면 undefined를 return한다.
function ParentOfParentOfParent(){
this.name = "부모의부모의부모";
}
function ParentOfParent(){
this.age = "부모의부모";
}
function Parent(){
this.gender = "부모"
}
function Child(){
this.key = "차일드";
}
//Child의 Prototype Object(프로토타입 객체)를 Parent로 지정
Object.setPrototypeOf(Child.prototype, Parent.prototype);
//Parent의 Prototype Object(프로토타입 객체)를 ParentOfParent로 지정
Object.setPrototypeOf(Parent.prototype, ParentOfParent.prototype);
//ParentOfParent의 Prototype Object(프로토타입 객체)를 ParentOfParentOfParent로 지정
Object.setPrototypeOf(ParentOfParent.prototype, ParentOfParentOfParent.prototype);
const a = new Child();
console.log(a.name) //"부모의부모의부모";
자식이 부모의 메서드를 사용하지 않고 덮어쓰는 경우
자식이 부모의 프로퍼티를 사용하지 않고 덮어쓰는 경우
OOP에 대해 쓰려다가 prototype을 먼저 정리하고 가야겠다는 생각이 들어서 prototype 정리로 빠졌다. 다음 글은 OOP에 대해 쓸 예정이다.
지금까지 썼던 글 중 가장 오랜 시간 이해하려고 애썼다.
여태 '참 모르고 써왔구나' 라는 생각이 들며 되돌아보게 된다.
참고자료
https://poiemaweb.com/js-prototype
https://developer.mozilla.org/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67