모던자바스크립트 Deep Dive "19장 프로토타입"을 요약해보자. 프로토타입이란 무엇인가?
자바스크립트는 명령형, 함수형, 프로토타입 기반의 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.
프로토타입 기반의 객체지향 프로그래밍 이 무엇일까?
프로토타입 : 프로토타입 객체의 줄임말. 프로토타입은 어떤 객체의 상위(부모) 객체의 역할을 하는 객체. 다른 객체에 공유 프로퍼티(메서드 포함)를 제공한다. 프로토타입을 상속받은 하위(자식) 객체는 상위 객체의 프로퍼티를 자신의 프로퍼티처럼 자유롭게 사용할 수 있다. 즉, 객체간 상속을 구현하기 위해 사용된다.
객체지향 프로그래밍 : 프로그램을 여러 개의 독립적인 단위, 즉 객체의 집합으로 표현하는 프로그래밍 패러다임이다.
상속 : 객체지향 프로그래밍의 핵심 개념. 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용하는 것이 상속. JS는 프로토타입을 기반으로 상속을 구현하여, 코드의 불필요한 중복을 제거한다.
상속에 의한 메서드 공유
상속에 의한 메서드 공유 코드
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getDiameter = function () {
return Math.PI * this.radius ** 2;
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);
console.log(circle1.getDiameter === circle2.getDiameter); // true;
console.log(circle1.getDiameter()); // 3.141592653589793
console.log(circle2.getDiameter()); // 12.566370614359172
[[Prototype]] 내부 슬롯에는 직접 접근할 수 없지만, 위 그림처럼
__prototype__
접근자 프로퍼티를 통해 자신의 프로토타입에 간접적으로 접근할 수 있다. 그리고 프로토타입은 자신의 constructor 프로퍼티를 통해 생성자 함수에 접근할 수 있고, 생성자 함수는 자신의 prototype 프로퍼티를 통해 프로토타입에 접근할 수 있다.
__proto__
접근자 프로퍼티__proto__
접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다__prototype__
아래의 항목들이 student 객체의 프로토타입인 Object.prototype이다.__prototype__
접근자 프로퍼티를 통해 student 객체의 [[Prototype]] 내부 슬롯이 가리키는 객체인 Object.prototype에 접근한 결과를 콘솔에 출력한 것.__prototype__
접근자 프로퍼티를 통해서 프로토타입을 가리키는 [[Prototype]] 내부 슬롯에 접근할 수 있다
- 접근자 프로퍼티 : 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수(getter/setter)로 구성된 프로퍼티
__prototype__
접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라 Object.prototype의 프로퍼티다. 모든 객체는 상속을 통해Object.prototype.__proto__
접근자 프로퍼티를 사용할 수 있다
Object.prototype
모든 객체는 프로토타입의 계층 구조인 프로토타입 체인에 묶여있다. JS 엔진은 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때, 해당 객체에 접근하려는 프로퍼티가 없다면__prototype__
접근자 프로퍼티가 가리키는 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 프로토타입 체인의 종점, 즉 프로토타입 체인의 최상위 객체는 Object.prototype이며, 이 객체의 프로퍼티와 메서드는 모든 객체에 상속된다.
함수 객체가 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다
// 함수 객체는 prototype 프로퍼티를 소유한다
(function () {}).hasOwnProperty('prototype'); // true
// 일반 객체는 prototype 프로퍼티를 소유하지 않는다
({}).hasOwnProperty('prototype'); // false