본문 바로가기
JS/JS 공부는 다다익선 [모던자바스크립트]

JS 공부는 다다익선 - 7. prototype

by spare8433 2023. 9. 21.

1. 프로토타입 객체

자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다. 이러한 부모 객체를 **Prototype(프로토타입) 객체 또는 줄여서 Prototype(프로토타입)이라 한다.

 

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



2. [[Prototype]] vs prototype 프로퍼티

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

 

함수도 객체이므로 [[Prototype]] 가지면서 함수 객체는 일반 객체와는 달리 prototype 프로퍼티도 소유하게 된다.



[[Prototype]]

 

  • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
  • 자바스크립트 엔진 내부에서 프로토타입 체인을 구현하는 데 사용되며 개발자가 직접 접근 또는 조작할 수 없다. (프로토 타입에 접근하려면 Object.setPrototypeOf()Object.getPrototypeOf()를 사용하는 것이 권장된다.)
  • 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리킨다.



prototype 프로퍼티

  • 함수 객체만 가지고 있는 프로퍼티이다.
  • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.



3. constructor 프로퍼티

프로토타입 객체의 constructor 프로퍼티는 일반적으로 프로토타입 객체를 만든 생성자 함수(prototype 객체의 생성자 함수)를 가리킵니다.



4. Prototype chain

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



4.1 객체 리터럴 방식으로 생성된 객체의 프로토타입 체인

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



Object literal Prototype chaining



4.2 생성자 함수로 생성된 객체의 프로토타입 체인

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



constructor function prototype chaining



※ 결국은 모든 객체의 부모 객체인 Object.prototype 객체에서 프로토타입 체인이 끝나기 때문에 Object.prototype 객체를 프로토타입 체인의 종점(End of prototype chain)이라 한다.



5. 프로토타입 객체의 확장

프로토타입 객체도 객체이므로 일반 객체와 같이 프로퍼티를 추가/삭제할 수 있다. 그리고 이렇게 추가/삭제된 프로퍼티는 즉시 프로토타입 체인에 반영된다.



6. 원시 타입(Primitive data type)의 확장

자바스크립트에서 원시 타입(숫자, 문자열, boolean, null, undefined)을 제외한 모든것은 객체이다. 그런데 아래 예제를 살펴보면 원시 타입인 문자열이 객체와 유사하게 동작한다.

 

var str = 'test';
console.log(typeof str);                 // string
console.log(str.constructor === String); // true
console.dir(str);                        // test

var strObj = new String('test');
console.log(typeof strObj);                 // object
console.log(strObj.constructor === String); // true
console.dir(strObj);
// {0: "t", 1: "e", 2: "s", 3: "t", length: 4, __proto__: String, [[PrimitiveValue]]: "test" }

console.log(str.toUpperCase());    // TEST
console.log(strObj.toUpperCase()); // TEST



원시 타입 문자열과 String() 생성자 함수로 생성한 문자열 객체의 타입은 분명이 다르다. 원시 타입은 객체가 아니므로 프로퍼티나 메소드를 가질수 없다.

 

원시 타입으로 프로퍼티나 메소드를 호출할 때 원시 타입과 연관된 객체로 일시적으로 변환되어 프로토타입 객체를 공유하게 되어 속성 및 내장메서드를 활용할 수 있지만 결과적으로 객체가 아니므로 프로퍼티나 메소드를 추가 및 변경은 불가하다.

 

※ 자바스크립트는 표준 내장 객체의 프로토타입 객체에 개발자가 정의한 메소드의 추가를 허용한다. 따라서 String 객체의 프로토타입 객체 String.prototype에 메소드를 추가할 수 있고 이 때원시 타입, 객체 모두 메소드를 사용할 수 있다.



7. 프로토타입 객체의 변경

프로토타입 객체를 확장시키는 경우 즉시 프로토타입 체인에 적용된다. 근데 만약 프로토타입의 객체자체를 새로 다른 임의의 객체로 변경 경우 이후의 생성되는 객체들은 이전에 객체들과 다른 프로토타입 객체를 가지게 된다.

 

부모 객체인 프로토타입을 동적으로 변경할 수 있기 때문에 이러한 특징을 활용하여 객체의 상속을 구현할 수 있다.



8. 프로토타입 체인 동작 과정

객체의 프로퍼티를 참조하는 경우, 해당 객체에 프로퍼티가 없는 경우, 프로토타입 체인이 동작한다.

 

먼저 해당 객체 자체에서 검색하고, 찾지 못하면 프로토타입 체인을 따라 부모 객체로 이동하여 검색을 시도합니다. 이 과정은 계속해서 부모 객체의 프로토타입으로 이동하면서 계속됩니다. 이렇게 하여 상속된 속성과 메서드를 찾을 때까지 계속 검색합니다.



참고


https://poiemaweb.com/js-prototype