아직도 어려운 자바스크립트 프로토타입(Prototype)

pixelstudio·2021년 2월 15일
0

JS프로토타입

목록 보기
1/1

흔히들 말하는 자바스크립트는 객체지향 언어에 싱글스레드로 동작하며, 프로토타입기반의 언어라고들 한다. 프로토타입 막상 찾아보면 온갖 이해하기 힘든 내용들이 많이 기제되어있다. 차근차근 파헤쳐가면서 알아가보고자 한다.

자바스크립트는 프로토타입 기반 언어이다. 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(Prototype object)를 가진다는 의미이다.-MDN

쉽게 말한다면, 자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되있는데, 부모 객체의 프로퍼티나 메소드를 상속받아 사용할 수 있게 된다. 이러한 부모 객체를 Prototype 객체또는 Prototype이라고 한다.

아래에 간단한 예제가 있다.

function Person(name, gender){
 this.name = name;
 this.gender = gender
}

그리고 인스턴스가 두개의 주어졌다.

const persA = new Person('kim', 'male');
const persB = new Person('Park', 'female'); 

new라는 키워드를 통해 Person함수는 생성자(constructor) 자격이 부여되었고, 동시에 프로토타입 객체가 생성되었다. 왜 이렇게 되는지 가장먼저 프로토타입 객체가 뭔지 알아보자.

프로토타입 객체(Prototype Object)

자바스크립트에서 객체는 함수(Function)로 생성된다.

let obj = {};

obj는 중괄호({ })라는 리터럴을 담고있지만 함수랑 전혀 상관없는 코드로 보인다.

let obj = new Object();

하지만 Object가 자바스크립트에서 기본적으로 제공하는 함수이며, Function, Array도 모두 함수로 정의되어 있다.

이게 왜 프로토타입 객체랑 상관이 있는지 확인해 보고자 한다.
함수를 생성하게 되면 생성자(constructor)가 주어진다.

동시에 함수의 Prototype Object도 같이 생성된다.

즉, 생성자(constructor)는 프로토타입 객채(prototype Object)와 같이 생성된 함수를 가르키고있고, 이 프로토타입 객체는 .__proto 를 가지고 있는데, 이것은 자신의 부모 객체를 가르키고있다.

function Person(name, gender){
 this.name = name;
 this.gender = gender
}

Person.prototype.age = 21;

const persA = new Person('kim', 'male');
const persB = new Person('Park', 'female'); 

위의 코드에서 persA.age를 개발자도구에 입력해보면 다음과 같이 나온다.

프로토타입 객체는 일반적인 객체이므로, 속성을 마음대로 추가/삭제를 할 수 있게된다. 그러니 persA와 persB는 Person함수를 통해 생성됬으니, Person.prototype을 참조할 수 있게된다.

ECMAScript spec에서는 ** 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯(internal slot)를 가진다. [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는데 사용된다. [[Prototype]] 객체의 데이터 프로퍼티는 get 액세스를 위해 상속되어 자식 객체의 프로퍼티처럼 사용할 수 있다. 하지만 set 액세스는 허용되지 않는다.** 라고 되어있다.

여전히 이해하기 어렵다. 그렇다면 좀 더 자세하게 펼쳐보자. 우선 [[Prototype]]의 값은 Prototype이며, .__proto를 통해 어떤 존재를 가르키는지 확인할 수 있다. 프로토타입 링크라고 하며, 직접 사용하기 위해서 .__proto를 쓴다.

위의 예제를 통해 확인해 보자

persA.__proto로 크롬 개발자도구를 열어 확인해보면 생성자(constructor)을 통해 자신의 부모객체 Person.prototype를 가르키고있다.

그래서 실제로 persA.name, persB.gender을 입력하면 동작이 된다. 크롬 개발자도구를 통해 확인해 보면 링크로 이어져 있기 때문이다.

[[Prototype]]인터널 슬롯prototype프로퍼티의 차이

위에 예제에서 생성된 인스턴스에는 prototype 프로퍼티가 존재하지 않는다.

위 이미지에서와 같이 prototype 프로퍼티는 함수 객체만 가지고 있는 프로퍼티이다.
Person()이라는 함수 객체를 persA나 persB와 같이 인스턴스로 구현했을 때 해당 인스턴스의 부모역할을 하는 프토토타입 객체를 가르킨다.

결과적으로 Prototype 프로퍼티나 [[Prototype]]인터널 슬롯은 각자의 관점의 차이가 있다.

인스턴스 persA의 .__proto는 자신을 생성한 Person()을 가르키고 있고, Person()의 .__proto 는 자신의 부모인 Function.prototype를 가르킨다.

프로토타입 객체는 constructor 프로퍼티를 갖게되는데 객체의 입장에서 자신을 생성한 객체를 가르킨다.

프로토타입 체인(Prototype Chain)

persA와 persB는 .name, .age외에도 다른 메소드를 사용할 수 있다. 하지만 persA나 B 자체에는 저런 메소드가 없는데, 이런 일이 가능한 이유는 단 하나의 속성 .__proto가 존재하기 때문이다.

persA.__proto로 족보를 들여다보면 Person함수의 prototype Object를 가르키고있다.

이번에는 prototype object의 조상을 찾아보자.

생성자를 통해 자신을 생성한 Object를 가르키고 있고, Object위로는 더이상 없다. 결국 Person은 Object로부터 상속받게 되고, persA나 B는 Person에게 상속받는다.

그러니까, persA와 B는 age, name과 같은 속성은 없지만, 이 속성을 찾기 위해 상위 프로토타입을 탐색하게 된다. 최상위인 Object의 Prototype Object까지 도달했는데 못찾았을 경우
undefined를 반환하게 된다.

이런 개념이 프로토타입 체인(prototype chain)이다.

생성자(Constructor) 프로퍼티

자바스크립트에서 생성자의 역활은 아래에 new키워드로 객체를 만들게 되면, 자신을 생성한 인스턴스의 부모객체를 가르키는 역할을 한다.

결국 다른 객체지향 언어를 흉내를 낼 뿐이지만 문법적인 편리함을 제공한다고 한다.

function Person(name, gender){
 this.name = name;
 this.gender = gender
}

Person.prototype.age = 21;

const persA = new Person('kim', 'male');
const persB = new Person('Park', 'female'); 

Person 함수를 호출할 때 new키워드를 붙이기만 하면 Person 함수 내의 this키워드의 문맥은 index나 window가 아닌 자기 자신 Person이 된다.

인스턴스(Instance)

인스턴스도 헷갈리는 개념중 하나이다. 객체지향(OOP) 개념에서 오브젝트(Object)와 인스턴스(Instance)

원문출처

profile
프론트엔드 개발자를 목표로 학습하며 스스로 디벨롭중입니다. 추후엔 백엔드를 제대로 학습할 예정입니다.

관심 있을 만한 포스트

0개의 댓글