본문 바로가기
JavaScript

Prototype

by oncerun 2021. 11. 28.
반응형

자바스크립트는 클래스 기반 객체지향 프로그래밍 언어와 달리 프로토타입 기반 객체지향 프로그래밍 언어이다.

 

클래스 기반 객체지향 프로그래밍 언어는 객체 생성 이전에 클래스를 정의하고 이를 통해 객체를 생성한다.

하지만 프로토타입 기반 객체지향 프로그래밍 언어는 클래스 없이도 객체를 생성할 수 있다.

 

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 그리고 이것은 객체지향의 상속 개념과 같이 부모 객체의 프로퍼티 및 메서드를 상속받아 사용할 수 있게 한다.

이러한 부모 객체를 Prototype 객체라고 한다.

 

프로토타입 객체는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용한다.

자바스크립트의 모든 객체는 [[Prototype]]이라는 internal slot를 가진다. [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는 데 사용된다.  

[[Prototype]] 객체의 데이터 프로퍼티는 get 액세스를 위해 상속되어 자식 객체의 프로퍼티처럼 사용할 수 있다. 하지만 set 액세스는 허용되지 않는다.

 

[[Prototype]]의 값은 Prototype 객체이며 __proto__ accessor property로 접근할 수 있다. __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf가 호출되어 프로토타입 객체를 반환한다.

 

 

객체를 생성할 때 프로토타입은 결정된다. 결정된 프로토타입 객체는 다른 임의의 객체되 변경할 수 있다. 이것은 부모 객체인 프로토타입을 동적으로 변경할 수 있다는 것을 의미한다. 

 

 

 

모든 객체는 자신의 프로토타입 객체를가리키는 [[Prototype]] 인터널 슬롯을 갖으며 상속을 위해 사용된다. 

자바스크립트는 함수도 객체이므로 [[Prototype]] 인터널 슬롯을 갖는다. 그런데 함수 객체는 일반 객체와는 달리 prototype 프로퍼티도 소유하게 된다. 

 

prototype 프로퍼티와 프로토타입 객체를 가리키는 [[Prototype]] 인터널 슬롯은 다르다. 이 둘은 모두 프로토타입 객체를 가리키지만 관점에 차이가 존재한다.

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

var foo = new Person('Lee');

console.dir(Person); // prototype 프로퍼티가 있다.
console.dir(foo);    // prototype 프로퍼티가 없다.

 

 

  • [[Prototype]]
    함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
    객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 function.prototype을 가리킨다.
  • prototype 프로퍼티
    함수 객체만 가지고  있는 프로퍼티이다.
    함수객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체를 가리킨다.

 

constructor 프로퍼티

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

 

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

const a = new Person('a');

 

Person() 생성자 함수에 의해 생성된 객체를 a라 했을 때 a객체를 생성한 객체는 Person() 생성자 함수이다.

 

이때 a 객체 입장에서는 자신을 생성한 객체는 Person() 생성자 함수이며, foo 객체의 프로토타입 객체는 Person.prototye이다.  따라서 프로토타입 객체 Person.prototype의 construcot 프로퍼티는 Person() 생성자 함수를 가리킨다.

 

 

 

Prototype chain

자바스크립트는 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때 객체에 접근하려는 프로퍼티 또는 메서드가  없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메서드를 차례대로 검색한다. 이것을 프로토타입 체인이라고 한다.

 

1. 객체 리터럴 방식

 객체 리터럴 방식으로 생성된 객체는 결국 빌드인 객체인 Object() 생성자 함수로 생성하는 것을 단순화시킨 것이다.

자바스크립트 엔진은 객체 리터럴로 객체를 생성하는 코드를 만나면 내부적으로 Object() 생성자 함수를 사용하여 객체를 생성한다. 

 

Object()  생성자 함수는 함수객체이기 때문에 일반 객체와 달리 prototype 프로퍼티가 존재한다.

객체가 생성되면 앞선 정의에 따라 Object()생성자 함수의 prototype이 참조하는 Object.prototype이 프로토타입 객체가 된다.  객체의 생성을 위해 사용된 Object() 생성자 함수는 Object.prototype의 constructor이다.

 

 

2. 생성자 함수로 생성된 객체

 

함수 선언식, 함수 표현식, Funtion() 생성자 함수를 이용해 함수를 정의할 수 있다.

 

함수 표현식으로 함수를 정의할 때 함수 리터럴 방식을 사용한다.

const square = function (number) {
	return number * number;
};

함수 선언식의 경우 자바스크립트 엔진이 내부적으로 기명 함수 표현식으로 변환한다.

const square = function square(number) {
	return number * number;
};

 

함수 선언식, 함수 표현식 모두 함수 리터럴 방식을 사용하며, 함수 리터럴 방식은 function() 생성자 함수로 함수를 생성하는 것을 단순화시킨 것이다. 결국 함수 정의 방식 모두 Function() 생성자 함수를 통해 함수 객체를 생성한다.

그렇기에 모든 함수 객체의 prototype 객체는 Function.prototype이다. 생성자 함수도 함수 객체이므로 생성자 함수의 prototype 객체는 Function.prototype이다.

 

 

foo 객체의 프로토타입 객체 Person.prototype 객체와  Person() 생성자 함수의 프로토타입 객체인 Function.prototype의 프로토타입 객체는 Object.prototype 객체이다. 결국 모든 객체의 부모 객체인 Object.prototype 객체에서 프로토타입 체인이 끝나기 때문에 Object.prototype 객체를 프로토타입 체인의 종점이라고 한다.

 

 

 

 

프로토타입 객체의 변경

 

객체를 생성할 때 프로토타입은 결정된다. 결정된 프로토타입 객체는 다른 임의의 객체로 변경할 수 있다. 이것은 부모객체인 프로토타입을 동적으로 변경할 수 있다는 것을 의미한다. 이러한 특징을 활용하여 객체의 상속을 구현할 수 있다.

 

이때 프로토타입객체를 변경하면 프로토타입 객체 변경 시점 이전에 생성된 객체는 기존 프로토타입 객체를 [[Prototype]]에 바인딩하고 있으며,  프로토타입 객체 변경 시점 이후에 생성된 객체는 변경된 프로로 타입 객체는 인터럴 슬롯에 바인딩한다.

반응형

'JavaScript' 카테고리의 다른 글

JS의 부정확한 계산  (0) 2021.12.03
export, import  (0) 2021.11.28
JavaScript Execution Context  (0) 2021.11.27
Number Property  (0) 2021.11.22
구조 분해 할당  (0) 2021.10.23

댓글