프로토타입... 부트캠프 동기분들 사이에서 악명높기로 소문난 녀석...
저도 처음으로 맛보려고합니다
프로토타입??
자바스크립트는 프로토타입 기반언어라고 불린다.
이유는 모든 객체들이 메소드와 속성들을 상속받기 위한
템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미.
사실, 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의
prototype이라는 속성에 정의되어 있다.
자바스크립트는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거.
중복을 제거하는 방법은 기존의 코드를 적극적으로 재사용하는 것
예제를 보며 살펴보자
위의 예제의 생성자함수는 문제가 있다 무슨문제일까!??
radius 프로퍼티 값은 일반적으로 인스턴스마다 다르다.
하지만 getArea 메서드는 모든 인스턴스가 동일한 내용의 메서드를 사용하므로
단 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직.
하지만 위의 생성자 함수는 인스턴트를 생성할 때마다 메서드를 모든 인스턴스가 중복소유
이처럼 생성자 함수에 의해 생성된 모든 인스턴스가 동일한 메서드를 중복 소유하는 것은
메모리를 불필요하게 낭비함.
자바스크립트는 프로토타입을 기반으로 상속을 구현한다. 상속을 통해 불필요한 중복을 제거하자
Circle 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입,
즉 상위(부모)객체 역할을 하는 Circle, prototype의 모든 프로퍼티와 메서드를 상속받음.
따라서, 자신의 상태만 나타내는 radius 프로퍼티만 개별소유,
내용이 동일한 메서드는 상속을 통해 공유하여 사용
프로토타입 객체(프로토타입)
그럼 프로토타입 객체를 가진다는건 알겠는데 그럼 프로토타입 객체가 뭐야??
프로토타입 객체(프로토타입)란:
객체지향 프로그래밍의 근간을 이루는 객체 간 상속을 구현하기 위해 사용.
쉽게 말하면
클래스, 생성자 함수 | 부모 |
인스턴스 | 자식 |
프로토타입 | 유전자 |
이렇게 정리가 되어 프로포타입을 상속받는 하위(자식) 객체는 상위 객체의 프로퍼티를
자신의 프로퍼티처럼 자유롭게 사용할 수 있다.
인스턴스는 이런식으로 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입,
즉 자신의 [[Prototype]] 내부슬롯이 가리키는 프로토타입에 간접적으로 접근 가능
__proto__ 접근자 프로퍼티???
모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입,
즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.
유의해야 할것은 __proto__ 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라
Object.prototype 의 프로퍼티이다.
__proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유
[[Prototype]] 내부 슬롯의 값, 즉 프로토타입에 접근하기 위해 접근자 프로퍼티를 사용하는 이유는
상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위함이다.
위 예제같은 코드가 에러없이 정상적으로 서로가 자신의 프로토타입이 되는
비정상적인 프로토타입 체인이 만들어지기 때문에 __proto__ 접근자 프로퍼티는 에러를 발생시킴.
프로토타입 체인은 단방향 링크드 리스트로 구현되어야 한다.
즉, 프로퍼티 검색방향이 한쪽 방향으로만 가야한다~
따라서 무조건적으로 프로토타입을 교체할 수 없도록
__proto__ 접근자 프로퍼티를 통해 접근하고 교체하도록 구현되어 있음
근데 이런 좋은줄만 알았던 __proto__를 코드 내에서 직접 쓰지말라고...??
이유는 모든 객체가 __proto__ 접근자 프로퍼티를 사용할 수 있는게 아니기 때문이란다.
// obj는 프로토타입 체인의 종점이다. 따라서 Object.__proto__ 를 상속받을 수 없다.
const obj = Object.create(null);
위같이 Object.prototype을 상속받지 않는 객체를 생성할 수도 있기에,
__proto__ 접근자 프로퍼티를 사용할 수 없는 경우가 있다.
따라서,
__proto__ 접근자 프로퍼티 대신 프로토타입의 참조를 취득할 때는,
Object.getPrototypeOf 메서드 사용을 권장
프로토타입을 교체하고 싶은 경우에는
Object.setPrototypeOf 메서드 사용을 권장