자바스크립트의 상속/프로퍼티 검색 메커니즘인 프로토타입 체인에 대해 알아보자.

이민선(Jasmine)·2023년 3월 15일
0
post-thumbnail

자바스크립트는 여타 클래스 기반의 객체지향 프로그래밍 언어처럼 접근 제한자(ex. public, private, protected)가 없기 때문에 객체지향 프로그래밍 언어가 아니라는 오해를 많이 받는다.


논란에 이리 치이고 저리 치이는 JS를 볼 때마다 눈에서 땀이 난다.

하지만 자바스크립트는 사실 힘숨찐이다. 객체지향 프로그래밍을 구현하기 위한 강력한 무기를 가지고 있는데, 바로 프로토타입 체인이다. 프로토타입 체인이라는 상속 및 프로퍼티 검색 메커니즘을 통해 개발 비용을 현저히 줄일 수 있는 잠재력을 지니고 있다.

이번 포스팅에서는 가장 먼저 프로토타입 체인을 이해하기 위한 생성자함수/프로토타입/인스턴스 간의 관계도에 눈도장을 찍어보며 시작하려고 한다. 이후에 자바스크립트에서 프로토타입 체인을 통해 상속 및 프로퍼티 검색이 어떠한 메커니즘으로 이루어지는지, 또 코드 재사용 측면에서 어떠한 이점이 있는지 하나씩 살펴보자.

1. 생성자 함수, 인스턴스, 프로토타입의 관계

객체를 생성하는 방식에는 여러 가지가 있지만, 그 중에서도 생성자 함수 (또는 클래스)를 이용하여 객체를 생성할 때 생성자 함수/인스턴스/프로퍼티의 관계를 가장 편하게 이해할 수 있다.

1) Programmer라는 생성자 함수는 Programmer.prototype의 constructor이자 jasmine이라는 instance의 constructor이다.

2) Programmer.prototype이라는 프로토타입은 jasmine이라는 instance의 부모 객체이자, Programmer라는 생성자함수의 프로토타입이다.

3) jasmine이라는 instance는 Programmer라는 생성자함수의 instance이자, Programmer.prototype의 자식 객체이다.

이를 코드로 나타내면 아래와 같다.

객체가 자신의 상위 객체에 접근할 때에는 __proto__ 접근자 프로퍼티를 사용하며, 생성자함수가 자신의 prototype에 접근할 때에는 .prototype을 사용한다. 그리고 프로토타입 객체가 자신의 생성자 함수에 접근할 때에는 constructor 프로퍼티를 사용한다.

이렇게 프로토타입, 생성자 함수, 인스턴스 간의 삼각 관계까지는 확인을 해보았다.

여기서 끝나지 않는다. Programmer.prototype의 프로토타입 객체도 있다구! 바로 Object.prototype이다.

오 그럼 jasmine의 부모 객체가 Programmer.prototype이면 Object.prototype은 jasmine의 조상이라도 되는건가? 댓츠 롸잇! 이러한 프로토타입 간의 계층 구조를 바로 프로토타입 체인이라고 하는 것이다.
Object.prototype은 프로토타입 체인에서 늘 최상위에 위치하는 객체이므로 프로토타입 체인의 종점이다.

근데 그래서 이런 객체들 간의 계층 구조가 도대체 무슨 의미가 있다는 걸까?
바로 프로토타입 객체지향 프로그래밍에 있어 아주 중요한 의미를 가지는 상속과 프로퍼티 검색 메커니즘이다. 하나씩 살펴보자.

2. 상속

결론부터 이야기하자면, 프로토타입 체인으로 상속을 구현하면 코드의 재사용성 측면에서 이점이 크다.
그 이점을 활용하지 못하고 있는 코드를 먼저 구경해보자.

// Jasmine: React
// Andy: Vue
// Mike: Flutter

각 프로그래머가 어떤 프레임워크를 사용하는지 이름과 함께 console 출력해주는 메서드인 function word를 생성자함수 내에 정의해 놓았다.
프로그래머가 100명 200명 증가하고 계속해서 new Programmer로 객체를 찍어내야 한다면?
function word라는 메서드도 사람 수에 비례하여 같이 찍어내야 할텐데 메모리 낭비가 아주 심할 것이다.
중복 생성 중복 소유 타파하자!

이 때 프로토타입 두두등장.
function word를 계속 찍어내기 버겁다고? 그렇다면 나에게 맡겨 하하하!

// Jasmine: React
// Andy: Vue
// Mike: Flutter

function word를 생성자 함수가 아닌 생성자 함수의 prototype의 메서드로 정의하는 것이다.
아니 그럼 생성자함수의 메서드도 아닌데 instance인 개발자들은 어떻게 이름과 프레임워크를 출력할 수 있는 것인가? 답은 상속에 있다.

위에서 살펴본 것처럼 각 객체는 프로토타입 체인으로 연결되어 있으며, Programmer.prototype은 jasmine, andy, mike의 부모 객체이다. 따라서 각 개발자(인스턴스 객체)는 자신의 소유가 아닌 function word라는 메서드를 부모 객체로부터 상속 받아 사용할 수 있는 것이다.

이렇게 상속을 구현한다면 개발자 객체를 100개 200개 찍어내더라도 Programmer.prototype 한 군데에만 메서드를 등록해놓으면 된다. 코드의 재사용성 측면에서 아주 효율적이다! 모든 인스턴스가 동일한 메서드를 사용하므로 하나를 언제든지 공유해서 사용할 수 있는 것이다. (진정한 창조 경제는 이런 것이 아닐까)

이처럼 프로토타입 체인을 통한 프로퍼티나 메서드의 상속은 검색을 통해 이루어진다. 검색 과정도 한 번 살펴보자.

3. 검색

위에서 jasmine.word를 호출했을 때 자바스크립트 엔진은 먼저 무엇을 했을까? jasmine 객체부터 찾아간다. jasmine 객체에 word라는 메서드가 있는지 검색해보고, 있으면 word를 호출했겠지만 jasmine에게는 없다.

다음 단계가 중요하다. jasmine 객체의 부모 객체인 Programmer.prototype을 찾아가는 것이다. Programmer.prototype에 잘 맡겨둔 메서드 word가 있으므로 비로소 word를 호출할 수 있게 되는 것이다.

만약 부모 객체의 부모 객체 혹은 그보다 상위의 객체에게 있는 프로퍼티 또는 메서드라면? 역시 상속 받을 수 있다. Programmer.prototype의 부모 객체는 Object.prototype이고, 후손 객체들 역시 Object.prototype의 프로퍼티와 메서드를 상속 받을 수 있는 것이다.

예를 들어 hasOwnProperty라는 메서드는 Object.property의 메서드이다. Object는 프로토타입 체인에서 최상위 객체이므로 (거의 시조새) 의도적으로 프로토타입 체인 연결을 끊어버리지 않는 이상 후손 객체가 hasOwnProperty와 같은 Object.property의 메서드를 상속받아 사용할 수 있는 것이다.

참고: 모던 자바스크립트 딥다이브 (이웅모 저)

profile
기록에 진심인 개발자 🌿

0개의 댓글