October 18, 2021

개발을 하다 보면 기존에 있는 기능을 가져와 확장해야 하는 경우가 생깁니다.

사람에 관한 프로퍼티와 메서드를 가진 user라는 객체가 있는데, user와 상당히 유사하지만 약간의 차이가 있는 admin과 guest 객체를 만들어야 한다고 가정해 봅시다. 이때 "user의 메서드를 복사하거나 다시 구현하지 않고 user에 약간의 기능을 얹어 admin과 guest 객체를 만들 수 있지 않을까?"라는 생각이 들 겁니다.

자바스크립트 언어의 고유 기능인 프로토타입 상속(prototypal inheritance) 을 이용하면 위와 같은 생각을 실현할 수 있습니다.

[[Prototype]]

자바스크립트의 객체는 명세서에서 명명한 [[Prototype]]이라는 숨김 프로퍼티를 갖습니다. 이 숨김 프로퍼티 값은 null이거나 다른 객체에 대한 참조가되는데, 다른 객체를 참조하는 경우 참조 대상을 '프로토타입(prototype)'이라 부릅니다.

프로토타입의 동작 방식은 '신비스러운’면이 있습니다. object에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면 자바스크립트는 자동으로 프로토타입에서 프로퍼티를 찾기 때문이죠. 프로그래밍에선 이런 동작 방식을 '프로토타입 상속’이라 부릅니다. 언어 차원에서 지원하는 편리한 기능이나 개발 테크닉 중 프로토타입 상속에 기반해 만들어진 것들이 많습니다.

let animal = {
  eats: true
};
let rabbit = {
  jumps: true
};

*rabbit.__proto__ = animal; // (*)*// 프로퍼티 eats과 jumps를 rabbit에서도 사용할 수 있게 되었습니다.
*alert( rabbit.eats ); // true (**)*alert( rabbit.jumps ); // true

(*)로 표시한 줄에선 animal이 rabbit의 프로토타입이 되도록 설정하였습니다.

(**)로 표시한 줄에서 alert 함수가 rabbit.eats 프로퍼티를 읽으려 했는데, rabbit엔 eats라는 프로퍼티가 없습니다. 이때 자바스크립트는 [[Prototype]]이 참조하고 있는 객체인 animal에서 eats를 얻어냅니다. 아래 그림을 밑에서부터 위로 살펴보세요.

프로토타입 체이닝엔 두 가지 제약사항이 있습니다.

  1. 순환 참조(circular reference)는 허용되지 않습니다. __proto__를 이용해 닫힌 형태로 다른 객체를 참조하면 에러가 발생합니다.
  2. __proto__의 값은 객체나 null만 가능합니다. 다른 자료형은 무시됩니다.

여기에 더하여 객체엔 오직 하나의 [[Portotype]]만 있을 수 있다는 당연한 제약도 있습니다. 객체는 두 개의 객체를 상속받지 못합니다.

for…in 반복문

for..in은 상속 프로퍼티도 순회대상에 포함시킵니다.