class를 통해 객체지향을 구현하는 C++이나 java, python과 같은 다른 언어들과는 달리, javascript는 프로토타입을 통해 객체지향을 구현한다는 특징을 가진다.
물론 ES6부터는 자바스크립트에 클래스 구문이 추가되었기는 하지만, 그 본질을 보면 javascript는 여전히 클래스를 통해서가 아닌 프로토타입을 통해 객체지향을 구현하고 있다. 그저 사용하기 편리하도록 껍데기만을 제공할 뿐이다(문법 설탕, syntax sugar).
다음은 생성자로 객체를 생성하는 코드이다.
function Circle(center, radius) {
this.center = center;
this.radius = radius;
this.area = function() {
return Math.PI * this.radius * this.radius;
};
}
var c1 = new Circle({x: 0, y: 0}, 2.0);
var c2 = new Circle({x: 2, y: 5}, 3.0);
이 코드에는 문제점이 있는데, Circle
생성자를 통해 만들어진 각각의 인스턴스들(c1
, c2
, …)이 모두 area
함수를 가지게 된다는 것이다.
이때문에 인스턴스를 여러 개 생성하면 같은 작업을 하는 메서드를 인스턴스 개수만큼 생성하게 되어 메모리를 낭비하게 된다.
function Circle(center, radius) {
this.center = center;
this.radius = radius;
}
Circle.prototype.area = function() {
return Math.PI * this.radius * this.radius;
};
var c1 = new Circle({x: 0, y: 0}, 2.0);
var c2 = new Circle({x: 2, y: 5}, 3.0);
위 문제는 이와 같이 프로토타입을 통해 해결할 수 있다.
javascript의 모든 함수 객체는 prototype
이라는 프로퍼티를 갖고 있는데, 이는 상속시키려는 멤버들이 정의된 객체를 가리킨다(프로토타입 객체).
위의 예제에서는 Circle의 프로토타입 객체에 함수 area
를 저장함으로써, 인스턴스를 여러 개 생성하더라도 메서드를 공유할 수 있도록 했다.
그렇다면 c1
과 c2
는 어떻게 area
함수를 찾아 실행할 수 있는 것일까?
모든 객체는 내부 프로퍼티 [[Prototype]]
를 가지며, 이는 그 객체에게 상속을 해 준 부모 객체를 가리킨다. (일반적으로 __proto__
프로퍼티에 [[Prototype]]
이 저장됨)
[[Prototype]]
은 위에서 언급했던, 프로토타입 객체를 가리키는 prototype
프로퍼티와는 다른 것이다.
만약 위 코드 상황에서 c1.area();
와 같이 area
함수를 호출하면, 다음과 같이 area
함수를 검색한다.
c1
)가 area
라는 프로퍼티를 소유하고 있는지 확인한다. area
를 찾을 수 없다면, c1.__proto__
가 가리키는 Circle.prototype
이 area
라는 프로퍼티를 소유하고 있는지 확인한다.area
를 찾아 이를 사용한다.이와 같이 자신의 [[Prototype]]
이 가리키는 프로토타입 객체를 차례대로 찾아나가며 프로퍼티를 찾는데, 이를 프로토타입 체인이라고 한다.
자바스크립트에서의 상속은 프로토타입 체인을 기반으로 구현된다.
함수 객체가 가지는 prototype
프로퍼티는 프로토타입 객체를 가리키며, 프로토타입 객체는 constructor
프로퍼티와 내부 프로퍼티([[Prototype]]
)을 가진다.
constuctor
프로퍼티는 그 함수 객체의 참조를 값으로 가지며, [[Prototype]]
프로퍼티는 상위 프로토타입 객체를 가리킨다.
function Circle(center, radius) {
this.center = center;
this.radius = radius;
}
Circle.prototype.area = function() {
return Math.PI * this.radius * this.radius;
};
var c1 = new Circle({x: 0, y: 0}, 2.0);
var c2 = new Circle({x: 2, y: 5}, 3.0);
그렇다면 위에서 설명한 구조를 그림으로 나타내보자.
prototype
프로퍼티를 가지며, 이는 프로토타입 객체를 가리킨다.constructor
와 [[Prototype]]
프로퍼티를 가지며, 이는 각각 생성자 함수와 상위 프로토타입 객체를 가리킨다.[[Prototype]]
프로퍼티를 아래에서 위까지 차례대로 접근함으로써 그곳에 원하는 프로퍼티가 존재하는지 검색한다.c1
과 c2
는 new Circle(…)
과 같이 생성자를 통해 만들어진다.Object
이며, Object의 [[Prototype]]
은 null을 가리킨다.c1
과 c2
는 상위 프로토타입 객체의 프로퍼티에 접근할 수 있으므로, Circle.prototype
의 area
함수와 Object.prototype
의 toString
함수를 마치 자기 자신의 프로퍼티인 것처럼 사용할 수 있다.자바스크립트는 프로토타입 객체를 서로 이은 구조의 프로토타입 체인을 통해 객체지향 개념과 상속을 구현한다.
모던 자바스크립트 입문 (이소 히로시, 길벗출판사, 2021)
Object prototypes (https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes)