자바스크립트 핵심 (2): 프로토타입

Lee Yechan·2023년 7월 9일
0

Language - javascript

목록 보기
2/8

프로토타입

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를 저장함으로써, 인스턴스를 여러 개 생성하더라도 메서드를 공유할 수 있도록 했다.


그렇다면 c1c2는 어떻게 area 함수를 찾아 실행할 수 있는 것일까?


프로토타입 상속

모든 객체는 내부 프로퍼티 [[Prototype]] 를 가지며, 이는 그 객체에게 상속을 해 준 부모 객체를 가리킨다. (일반적으로 __proto__ 프로퍼티에 [[Prototype]]이 저장됨)

[[Prototype]]은 위에서 언급했던, 프로토타입 객체를 가리키는 prototype 프로퍼티와는 다른 것이다.

만약 위 코드 상황에서 c1.area(); 와 같이 area 함수를 호출하면, 다음과 같이 area 함수를 검색한다.

  1. 자기 자신 객체(c1)가 area라는 프로퍼티를 소유하고 있는지 확인한다.
  2. 만약 1. 에서 area를 찾을 수 없다면, c1.__proto__가 가리키는 Circle.prototypearea라는 프로퍼티를 소유하고 있는지 확인한다.
    1. 에서 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]] 프로퍼티를 가지며, [[Prototype]] 프로퍼티를 아래에서 위까지 차례대로 접근함으로써 그곳에 원하는 프로퍼티가 존재하는지 검색한다.
    • c1c2new Circle(…)과 같이 생성자를 통해 만들어진다.
    • 모든 객체의 조상은 Object이며, Object의 [[Prototype]]은 null을 가리킨다.
    • 인스턴스 c1c2는 상위 프로토타입 객체의 프로퍼티에 접근할 수 있으므로, Circle.prototypearea 함수와 Object.prototypetoString 함수를 마치 자기 자신의 프로퍼티인 것처럼 사용할 수 있다.

정리

자바스크립트는 프로토타입 객체를 서로 이은 구조의 프로토타입 체인을 통해 객체지향 개념과 상속을 구현한다.

reference

모던 자바스크립트 입문 (이소 히로시, 길벗출판사, 2021)

Object prototypes (https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes)

profile
이예찬

0개의 댓글