본문 바로가기
이론/Frontend

JavaScript의 프로토타입 (Prototype of JavaScript)

by 유세지 2021. 9. 27.

지난 글에서 상속과 클래스를 설명하며 프로토타입과 밀접한 관련이 있다고 언급했었습니다. 자바스크립트에서 프로토타입은 객체를 상속받기 위해 필요한 프로퍼티입니다. 지금 당장 개발자 도구를 켜고 아무 object 객체를 생성하여 객체의 속성을 확인해보면 [[prototype]] 이라는 속성을 갖고있는 것을 알 수 있습니다.

 

 

자바스크립트의 객체는 상속되는 속성과 메소드들을 객체의 생성자에 있는 [[prototype]] 에 정의합니다. 이 프로토타입 속성은 다른 상위 프로토타입 속성에게 또 다른 속성이나 메소드를 상속 받을 수 있습니다. 이러한 연쇄 과정을 프로토타입 체인이라고 부르며 자바스크립트는 이 프로토타입을 기반으로 동작하게됩니다.

 

 

프로토타입 체이닝

프로토타입 체이닝의 과정을 한 번 살펴보겠습니다. 하위 객체 obj에서 상위 객체인 parentObj에게 상속받은 프로퍼티를 검색하는 과정입니다.

 

let obj = new Object();
let parentObj = new Object();
parentObj.targetValue = "find!";

obj.targetValue // undefined

/* obj의 prototype을 parentObj로 연결 */
obj.__proto__ = Object.create(parentObj);

obj.targetValue // 'find!'

 

obj에 Object.create()를 이용해 parentObj를 상속받도록 하면 아래와 같은 구조를 갖습니다.

 

parentObj에 등록되어있던 targetValue 속성이 새롭게 생겼고, 내부에 또 다른 프로토타입 속성이 생긴 것을 알 수 있습니다. 이처럼 원래 객체에 없는 속성을 참조하게 되면 프로토타입을 타고 올라가 해당 속성을 찾아서 반환하는 구조로 되어있습니다. 프로토타입이 일종의 링크인 셈입니다. 그림으로 나타내면 아래와 같습니다.

 

 

obj의 프로토타입이 parentObj로 링크되어있고 (targetValue가 아닙니다) parentObj의 프로토타입도 존재합니다. 그림에는 보이지 않지만 객체는 기본적으로 최상위 객체인 Object로 연결되어있습니다. 우리가 parentObj로 연결해주기 전까지는 obj의 프로토타입도 Object에 연결되어 있었습니다. 이 때문에 그동안 우리가 따로 정의해준적은 없지만, toString()이나 valueOf()와 같은 객체의 기본적인 메서드들을 자연스럽게 사용할 수 있었던 것이죠.

 

 

 

관계 조사

우리는 new 키워드를 통해 새로운 객체 인스턴스를 만들었습니다. 이때 instanceof 키워드를 통해 인스턴스가 어떤 클래스나 함수에 포함되어 있는지 판별할 수 있었습니다. 이전 시간에 만들었던 Person 클래스와 Student 클래스를 가져오겠습니다.

 

let kim = new Student();

console.log(kim instanceof Student); // true
console.log(kim instanceof Person); // true

 

instanceof 키워드의 동작 원리를 살펴보면, 사실 객체의 프로토타입을 통해 포함 여부를 확인합니다. 생성자의 prototype 속성이 객체의 프로토타입 체인 어딘가 존재하는지 판별하고, Boolean 값을 반환하게 됩니다. 즉, 프로토타입 연쇄를 순회하는 과정에 키워드 오른쪽에 있는 함수의 프로토타입이 가리키는 객체가 있는지를 확인하는 것인데, 이렇게 되면 객체가 해당 함수의 계통인지만 확인할 수 있고 실제 객체와 객체 사이의 비교에서 서로 프로토타입으로 연결되어 있는지는 확인할 수 없습니다.

 

 

실제로 객체와 객체를 비교하려고 시도하면 위처럼 TypeError: not callable 에러를 받게 됩니다.

 

물론 따로 함수를 만들어서 프로토타입을 연결하고 사용하면 instanceof 로도 관계 조사를 할 수는 있겠지만, 이미 정의된 메서드를 두고 굳이 새로 만들 필요는 없습니다. 그 대신 .isPrototypeOf() 을 사용하면 됩니다.

 

parentObj.isPrototypeOf(obj); // true
obj.isPrototypeOf(parentObj); // false

 

isPrototypeOf() 는 매개변수로 들어간 객체의 전체 [[Prototype]] 연쇄에 앞의 객체가 존재하는지의 여부를 검사합니다. 따라서 객체와 객체 사이의 프로토타입 비교에 사용하기 적합합니다.

 

 

 

정리

이번 포스팅에서는 클래스에 이어 자바스크립트의 프로토타입에 대해 살펴보았습니다. 자바스크립트는 클래스 기반 언어가 아닌, 프로토타입을 기반으로 한 언어이며 실제로 클래스 또한 프로토타입을 기반으로 설계되어 있습니다. extends 를 활용한 상속 대신 object.create() 를 통한 프로토타입 연결으로도 같은 효과를 볼 수 있으며, 프로토타입 체이닝을 이용해 그 과정을 확인해보았습니다.

 

다음 시간에는 위임에 대해 알아보겠습니다. 읽어주셔서 감사합니다.

반응형

댓글