♻️ 개발자로 재활용/🟢 JavaScript

프로토타입(prototypes)과 프로토타입 체인

BuleRatel 2022. 11. 21. 23:44

JS는 프로토타입 기반 언어(prototype-based language)이다. JS의 빠질 수 없는 개념이자, JS 그 자체라 이해가 어렵고 개념도 복잡할 것이다. 하지만 ‘프로토타입’을 한 마디로 설명하기는 조금 어렵다. 차근차근 이해하는 시간을 가져 보자.

 


프로토타입 기반 언어

앞서 객체 지향 언어에 대해 공부하며 클래스와 인스턴스에 대해 공부했다. 중요한 점은, JavaScript는 ‘객체 지향 패턴’으로 작성되긴 하지만, 엄밀히 말해 ‘객체 지향 언어’는 아니다. 이 말인즉슨, 객체 지향 언어에서 사용하는 class라는 개념이 없다는 말이다. 그럼 어떻게 객체 지향 패턴을 작성하느냐 → 바로 Prototype을 통해 class의 상속을 흉내내는 것이다. JS가 프로토타입 기반 언어라고 불리는 이유이다.

JS의 모든 객체들은 프로토타입(prototype)이란 은닉 속성을 가지고 있다. 우리는 객체에 속성과 메서드를 부여한다고 생각하지만, 사실 객체의 생성자인 prototype에 속성과 메서드가 부여된다. 모든 객체들은 객체의 프로토타입으로부터 속성과 메서드를 상속받는다. 이를 프로토타입 체인(prototype chain)이라고 한다.

참고로 ES6에서 class 문법이 새로 추가되었다. 하지만 이는 문법일 뿐, 여전히 JS는 프로토타입 기반 언어이다.

 

 

 


프로토타입 체인

Array 메서드를 위해 방문했던 MDN을 떠올려 보자. ‘Array’ 객체가 아닌, ‘Array의 프로토타입’에서 내장 메서드인 ‘push()’를 가져오고 있다.

 

 

const arr = [1, 2, 3];
arr.push(4);

console.log(arr) // [1, 2, 3, 4]

배웠던 방법대로, 임의의 배열에 push()를 사용해 보자. 겉으로 보기에 arr는 [1, 2, 3]만 담고 있는 것처럼 보인다. 하지만 push()라는 메서드를 사용할 수 있다. 우리의 arr에는 push라는 메서드가 없는데 어떻게 가능할까? 

바로 은닉된 prototype 링크를 따라가 탐색하는 것이다. Array.prototype에 이미 push()라는 메서드가 존재하기 때문에, 이를 부모로 둔 모든 배열은 Array.prototype에 있는 내장 메서드를 사용할 수 있는 것.

 

Array.prototype === arr.__proto__;
// true
// __proto__는 모든 객체가 가진 속성이다. 상위 프로토타입으로 접근할 수 있다.

인스턴스 객체의 key(위의 push)에 접근할 때, 해당 객체(위의 arr)에 key가 없다면 그 다음으로 상위 프로토타입(원형) 속성에 key가 있는지 확인한다. 상위에도 없다면 더 상위로 올라가서 탐색한다. 모든 일반 객체의 최상위 프로토타입은 내장 Object.prototype이다. 이 지점에서도 찾지 못하면 탐색을 종료한 뒤 undefined를 반환한다.

 

실제 콘솔 로그를 참고해 보자. arr.push는 Array.prototype에 이미 내장되었기에 찾아와 실행시킬 수 있다. 하지만 임의로 작성한 arr.anything과 관련된 속성 또는 메서드는 어디에도 존재하지 않는다. 때문에 undefined가 반환된다.

 

 

 


참고 링크