Prototype - 2. JavaScript에서의 Prototype

Jeong-ho·2022년 4월 21일
1

JavaScript

목록 보기
2/3
post-thumbnail
  1. Prototype 디자인 이론
  • 비트겐슈타인 : 용도의미론, 가족유사성
  • 로쉬 : 프로토타입 이론(원형의미론)
  • prototype 이론으로 javascript 이해하기
    • prototype으로 객체 지향 프로그래밍 해보기
    • 호이스팅
    • this
  1. JavaScript에서의 Prototype
  • 표준 내장 객체
  • [[Prototype]] 그리고 __proto__
  1. JavaScript에서의 Class
  • class의 구성
    • 필드 선언
    • constructor
    • 정적 속성
    • 메소드
  • class에서 상속
  • class 상속을 prototype으로 구현해보기

JavaScript에서의 Prototype

 이번 파트에서는 자바스크립트 내의 프로토타입에 대해 살펴보겠다. 인지 심리학 측면이 아닌, 실제 '자바스크립트는 프로토타입 기반의 언어'인 이유와 코드상으로 프로토타입이 어떻게 구성되어 있는지를 중점으로 다룰 예정이다.

표준 내장 객체(standard built-in object)

 string, number 같은 원시 타입들은 어떻게 메소드를 사용할 수 있을까? array의 경우에도 미리 내장된 여러 메소드는 어디서 나온 걸까?

 자바스크립트에서는 표준 내장 객체가 존재한다. 그리고 우리가 평소에 사용하는 여러 기능은 각각의 표준 내장 객체에 new 키워드를 붙여 인스턴스화 한 것이다. 표준 내장 객체는 생성자 함수로 이해하면 될 것 같다. 즉, 표준 내장 객체를 프로토타입으로 하여 기능들을 구현하기에 자바스크립트는 프로토타입 기반의 언어라고 할 수 있다.

 객체가 함수라고 하니 의아해 할 수 있는데, 자바스크립트에서 함수는 객체다. 재밌는 점은 원시 타입의 경우다. 문자열을 예로 들면, 자바스크립트에서 문자열과 string 객체는 엄연히 다르다. 그러나 우리는 원형 문자열에 string 메소드를 사용할 수 있다. 어떻게 그게 가능할까?

 자바스크립트는 자체적으로 원형 문자열을 string 객체로 변환한다.

let 나원형 = '나문자';
let 나객체 = new String('나문자');

console.log(나원형 === 나객체.valueOf()) // true

// 원형 문자열에 메소드를 쓸 경우
나원형.indexOf('') // === new String('나문자').indexOf('')

생성자 함수의 property

 mdn 문서를 통해 이 생성자 함수와 속성(변수 + 함수)에 대해 좀 더 살펴보도록 하자.

 해당 이미지는 mdn 문서에 있는 String 표준 내장 객체에 있는 목차다. 정적 메소드(static method)는 생성자 함수 내에 멤버로 정의한 메소드다. 물론 변수를 정의했다면, 정적 변수(혹은 속성, 이 글에서는 편의상 변수 + 함수를 속성으로 통칭하겠다)다. 함수가 객체기 때문에 가능한 부분이다.

function 나생성자 () {};

나생성자.나정적 = '나 정적 변수임';

console.log(나생성자.나정적) // 나 정적 변수임

// 쉬운 예로 배열인지 아닌지 확인 하는 isArray()는 정적 메소드다. 인스턴스에서는 사용할 수 없고 생성자 함수(표준 내장 객체)를 통해 호출할 수 있기 때문이다.
Array.isArray(나생성자) // false

// 만약 정적 변수가 아닌 해당 인스턴스에게 상속을 하고 싶다면 함수 내 this를 붙여 명시하면 된다.
function 나생성자투 () {
  this.나변수 = "나 인스턴스에 들어갈 변수임"
}

// new 키워드를 사용하면 this는 생성될 인스턴스 객체를 가리킨다.
let 나인스턴 = new 나생성투();

console.log(나인스턴) // 나생성투 { 나변수: "나 인스턴스에 들어갈 변수임" }

 해당 정적 속성들은 인스턴스에서는 쓸 수 없다. 무조건 생성자 함수를 통해서 실행이 가능하다. 그럼 우리가 일반적으로 쓰는, 인스턴스에서도 쓸 수 있는 속성들은 어디에 명시되어 있을까. 바로 prototype 속성이다. 위 이미지에 나온 인스턴스 속성(변수), 메소드가 다 이 prototype 속성에 정의된 것들이다.

// 표준 내장 객체인 String을 찍었을 때
console.log(String) // f String() { [native code] }

// String의 prototype을 찍으면, 우리가 평소에 쓰는 메소드, 변수가 나온다.
console.log(String.prototype)
// String {'', constructor: f, anchor: f, big: f, blink: f, ...}

 prototype 속성에 정의된 속성들은 new 키워드를 통해 생성된 인스턴스들에게 공유된다.

[[Prototype]] 그리고 __proto__

 그러면 어떻게 인스턴스 객체는 생성자 함수의 prototype 속성을 공유받을 수 있을까? 바로 [[Prototype]]을 통해서 가능하다.

 [[Prototype]]은 은닉 속성이다. 그리고 이 은닉 속성은 생성자 함수의 prototype 속성을 가리킨다. 가령 위의 이미지에 let insA = new protoA()가 실행될 때, 자바스크립트는 insA.[[Prototype]] = protoA.prototype을 수행한다.

 그리고 [[Prototype]] 속성은 그 내부 속성으로 또 다른 [[Prototype]]속성을 가지고 있는데, 이는 상위 생성자의 prototype 속성을 가리킨다. 위 이미지를 예시로 보자면, insA.[[Prototype]] = protoA.prototype이다. insA.[[Prototype]].[[Prototype]] = Object.prototype이다. 위 이미지에서 Object 표준 내장 객체의 prototype 속성에 명시되어 있는 여러 속성들을 확인할 수 있다. Object는 최상위 객체이기에 [[Prototype]]이 없다.

 만약 insA.toString()을 입력하면 무슨 일이 일어날까. 먼저 자바스크립트는 insA.[[Prototype]]에서 해당 메소드가 있는 지 찾는다. 없다면 insA.[[Prototype]].[[Prototype]]에서 해당 메소드를 찾는다. 이처럼 계속해서 상위 프로토타입 속성을 탐색하는 걸, 프로토타입 체인이라고 칭한다.

 [[Prototype]] 속성 중 constructor는 해당 프로토타입 속성을 가지고 있는 생성자 함수를 가리킨다. 객체를 프로토타입으로 지정한 생성자 함수는 새로운 인스턴스를 만들었을 때, 해당 속성이 존재하지 않는다.

function 나생성자A () {
  this.나변수A = "나변수A"
}

나생정자A.prototype.나변수B = "나변수B";

let 나인스턴A = new 나생성자A();

function 나생정자B () {
  this.나변수C = "나변수C";
}

나생정자B.prototype = 나인스턴A;

let 나인스턴B = new 나생정자B();

console.log(나인스턴B)
// 나생성자B {
//   나변수C : "나변수C"
//   [[Prototype]] : 나인스턴A {
//    나변수A : "나변수A"
//    [[Prototype]] : Object {
//     나변수B : "나변수B"
//     constructor : ƒ 나생성자A()
//     [[Prototype]] : Object // 최상위 객체의 프로토타입, 프로토타입 체인의 종결지점
//    }
//   }
// }

 [[Prototype]]은 ECMAScript에 명시된 표준이다. 그럼 __proto__은 뭘까. __proto__은 사실 표준은 아니나, 많은 브라우저에서 구현되어 사실상 표준 [[Prototype]]와 유사한 속성이다.

나가는 말

 지금까지 내용을 정리하면 다음과 같다.

  • 자바스크립트는 표준 내장 객체를 프로토타입 삼아, 여러 기능들을 구현하는 프로토타입 기반의 언어다.
  • 생성된 인스턴스 객체들은 은닉 속성인 [[Prototype]]을 통해 최상위 프로토타입 속성들을 공유받는다.

 아쉬운 점으로는 그리 깊이 있는 글이 아닌 것 같다. 찾아본다고 찾아봤지만, 필자가 이해하는 선에서 정리하다 보니 그렇게 된 것 같다. 자세한 내용을 원한다면, 참고한 블로그 및 해당 mdn 문서와 같이 보는 게 좋을 것 같다.

참고한 사이트

사이트1
사이트2
사이트3

0개의 댓글