[딥다이브] 19장 프로토타입 스터디 정리

Haz·2022년 3월 5일
0
post-thumbnail

드디어 객체지향형 프로그래밍을 하는 개발자라면 무조건 알아야 할 상속과 관련된 파트를 공부할 때가 왔다. 자바스크립트는 객체지향 언어지만, 흔히 대조하는 클래스 기반 객체지향 언어인 자바와는 달리 프로토타입 기반 객체지향 언어다. 그렇다고 자바스크립트에 클래스가 없는가? 그건 아니다. ES6 문법부터는 클래스가 도입됐다. 그렇다고 자바스크립트가 클래스 기반 언어로 짠!! 하고 변하는 건 아니기에 딥다이브 19장 도입부에서는 이것이 일종의 설탕이라고 언급하고 있다. 이미 만들어진 과자집 위에 올라가는 스프링클 같은 느낌이랄까? 본격적으로 책을 읽으며 공부를 해보려는데 16,17,18장이 모두 이 프로토타입을 공부하기 위한 빌드업이었다는 사실을 깨닫고 그냥 자바스크립트 원리 설명이겠거니~ 대충 넘겨버린 나 자신을 원망했다. 다시 봐야할 게 너무나 많았다.

프로토타입이란?

그렇담 도대체 프로토타입이 뭐길래 이미 자신만의 과자집을 공고히 만든 자바를 따라 클래스 기반으로 만들지 않고 자바스크립트는 새로운 과자집을 만든걸까? JS MDN에서는 프로토타입을 이렇게 소개하고 있다.

Javascript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용합니다.

즉, "000 기반의 객체지향 언어"라고 설명할 때 이 "000"은 결국 어떤 방식으로 객체를 상속시키는가에 대한 이야기라는 걸 알게 됐다. 자바스크립트는 프로토타입을 이용해 객체를 상속시키는 언어였던 것이다.

프로토타입은 객체를 상속하는 방식이기도 하지만, 객체가 만들어졌을 때 내장되어있는 하나의 속성(프로퍼티)을 일컫는 용어다. 모든 자바스크립트의 객체들은 메소드와 속성들을 상속 받기 위한 템플릿으로 이 프로토타입 객체를 가지게 된다. 즉, 상속되는 속성(프로퍼티)과 메소드들은 각 객체가 아니라 객체 생성자의 prototype이라는 프로퍼티에 정의되어 있는 것이다. 상속을 통해 메모리 사용을 줄이고, 불필요하게 중복되는 코드를 줄여 효율적인 프로그래밍이 가능하도록 돕는 것이 바로 프로토타입이다.

proto 접근자 프로퍼티

우선, 접근자 프로퍼티를 이해해보자. 접근자 프로퍼티는 자바스크립트 내부 슬롯과 내부 메서드에 간접적으로 접근하기 위한 프로퍼티다. 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수의 Get, Set 프로퍼티 어트리뷰트로 구성된 프로퍼티다.

¯¯proto¯¯(velog가 마크다운 형식을 쓰고 있어 언더바 두 개를 쓰면 볼드 처리가 되어 기호를 대체해서 사용했음. 이하 프로토 프로퍼티라고 칭함)는 Object.prototype의 접근자 프로퍼티다. 이 프로퍼티는 [[Prototype]]이라는 내부 슬롯의 값에 getter/setter 함수를 활용해 접근하여 값을 읽거나 교체한다.
프로토 프로퍼티를 활용하면 프로토타입 체인이라는 것이 형성된다. 프로토타입 체인은 쉽게 말해 상속의 방향성이다. 여기서 유의할 점은 프로토타입 체인이 항상 단방향이어야 한다는 것이다. 부모와 자식 객체 간의 프로토타입 체인이 양방향으로 구성될 경우 서로가 자신의 프로토타입이 되고, 체인 종점이 없어 프로토타입 체인에서 프로퍼티를 찾을 때 부모에서 자식으로, 자식에서 다시 부모로 끝없이 순환하게 되는 루프에 빠진다.
이를 막기 위해 딥다이브에서는 프로토 프로퍼티를 직접 사용하지 않을 것을 권장한다. 사실 읽으면서 이걸 얼마나 실무에서 활용할 수 있을지 의문이었지만, 그렇게 하라니 그러려고 한다.

여기서 잠깐! 프로토타입 체인이란 뭘까?

프로토타입 체인

자바스크립트는 내가 특정 객체의 프로퍼티를 활용하기 위해 접근할 때 그 객체의 프로퍼티가 있다면 [[Prototype]] 내부 슬롯의 참조를 따라 상속해준 부모 프로토타입의 프로퍼티를 검색하는데, 이 구조가 바로 프로토타입 체인이다. 즉, 상속을 구현하는 매커니즘으로 이해할 수 있다.

오버라이딩과 프로퍼티 섀도잉

아주 생소한 부분이 나왔다. 예전에 잠깐 스터디 팀원들과 코틀린을 공부할 때 오버라이딩은 들어본 적이 있다. 객체를 상속 받아 일부 프로퍼티를 변경하고 싶을 때 객체 선언 시 앞에 "override"를 쓰라고 말이다. 그걸 자바스크립트에서 보게될 줄은 몰랐는데 역시 공부는 하고 볼 일이다. 아무튼 다른 팀원들은 모두 자바 베이스라서 이 부분을 쉽게 이해했지만, 필자는 이런 건 난생 처음 봤기에 이해하기가 쉽지 않았다. 딥다이브의 예제를 함께 보자.

const Person = (function () {
  // 생성자 함수
  function Person(name) {
    this.name = name;
  }
  
  // prototype method
  Person.prototype.sayHello = function() {
    console.log('Hi! My name is ${this.name}');
  };
  
  return Person;
}());

부모 객체가 될 Person이라는 생성자 함수를 만들고 즉시 실행되도록 하는 예제다. 객체 prototype에 메소드를 추가하기 위해 콘솔에 이름을 찍는 sayHello 라는 함수를 만들어 할당해줬다. 그럼 이번에는 자식 객체가 될 인스턴스 메소드를 한 번 보자.

me.sayHello = function (){
  console.log('Hey! Again, introduce myself. My name is ${this.name}');
};

me.sayHello();

인스턴스 메소드를 만들었다. 보면 메소드 이름이 같다는 걸 알 수 있다. 그럼 과연 마지막에 sayHello라는 메소드를 호출했을 때 어떤 문장이 콘솔에 찍히게 될까?

바로 인스턴스 메소드다. 이게 바로 오버라이딩이다. 프로토타입과 인스턴스의 메소드명이 같을 때 인스턴스에서 만든 메소드는 덮어씌워지고, 프로토타입 메소드는 가려진다. 프로토타입 메소드가 가려지는 현상은 프로퍼티 섀도잉이라고 부른다.

오버라이딩과 오버로딩, 동일한 작동을 하는 두 가지 방식이 있는데 자바스크립트에서는 오버라이딩만 지원한다. 오버로딩을 arguments를 활용해서 비슷하게 구현할 수 있다고 하는데 지금은 별로 흥미가 생기지 않는다. 나중에 쓸 일이 있다면 그 때 다시 알아보도록 하자.

마무리

여기까지가 딥다이브 19.8장까지 내용이다. 오늘의 스터디는 여기까지 진행했는데 자바 베이스인 나머지 두 팀원들에게 이것저것 설명 들어가며 혼자 읽었던 것보다는 훨씬 빠르게 습득했다. 이제 문제는 이걸 활용한 코드를 찾는 건데... 어디서 찾아야 할 지 모르겠다. 아는 사람은 댓글에 남겨주시길!

profile
나도 재밌고, 남들도 재밌는 서비스 만들어보고 싶다😎

0개의 댓글