javaScript/초급(문법 위주)

자바스크립트 프로토타입 (JavaScript Prototype) 1편 (개념위주)

쿠쿠하마 2020. 10. 15. 22:07
반응형

1. 프로토타입이란 : 

자바스크립트에서는 모든 객체에, 혹은 사용자가 새로운 객체를 생성할 때, 자동으로 Prototype 프로퍼티를 심어 넣습니다. 그리고 이 프로퍼티는 숨겨진 프로퍼티이므로, 함부로 접근할 수 없고, 특정 함수를 통해 접근할 수 있습니다. 

(여기서 프로퍼티란 자바에서의 멤버필드라고 생각하시면 될 것 같습니다. 한글로 설명할 시에는 '속성'이라고 말합니다.)

 

*여기서 살짝 햇갈리는 것이 있습니다.

정확히 무엇을 프로토타입으로 지칭하는가?

저는 두 가지로 생각하고 있습니다. 

첫 번째로는 단순하게, 위 1번에서 설명했듯이 어떤 객체에나 있는 Prototype 프로퍼티를 프로토타입이라고 하는 겁니다. (사실 첫 번째나 두 번째 의미나 둘 다 이해하시면, 결국 같은 것임을 알 수 있습니다.)

두 번째로는 2번을 다 읽고 이어서 설명하겠습니다. 

 

2. 프로토타입의 역할은? 

프로토타입의 역할은 일단 '상속'입니다. 

자바스크립트에서는 객체간의 상속을 이 프로토타입을 서로 상속하는 것으로 이루어집니다. 

 

B라는 객체가 있는데, A라는 객체를 상속받고 싶다. (= 참조하고 싶다.) 라면,

B의 프로토타입 프로퍼티에 A객체를 통으로 넣어버립니다.  

이렇게 되면 B에서 A의 자원을 사용할 수 있습니다. 이것이 프로토타입의 특징중 하나인데, 만약 객체 B에서 없는 자원을 호출하게 되면 자바스크립트 엔진에서는 B의 프로토타입을 뒤져봅니다. 만약에 B에도 없고 B의 프로퍼티인 프로토타입 안을 봤는데도 없다면, 없는 것으로 그제야 에러 메시지를 띄어줍니다.

 

이 특징을 살펴보면 우리가 흔히 쓰는 자바스크립트의 내장함수들을 생각해 봤을 때 이해가 되는 부분이 있습니다. 

대표적으로 배열을 만들고 배열을 유용하게 쓸 수 있는 내장함수들 입니다.

여러분이 자바스크립트에서 배열 하나를 만들게 되면, 자바스크립트 엔진에서 자동으로 프로토타입이 만들어지고 그 안에 배열과 관련한 내장 함수들을 참조하도록 넣어줍니다. 때문에 여러분이 굳이 여러분이 만든 배열 안에 내장 함수를 따로 정의해주지 않아도 자동으로 유용한 배열 관련 함수들을 사용할 수 있는 것입니다.

 

자 그럼 위에 1번에서 못다 한 설명을 이어하겠습니다.

두 번째로는 서로 상속관계에 있을 때, 그러니깐 B의 Prototype 프로퍼티가 참조하는 객체가 A일 때(위 상황과 동일), 

이때 이 A라는 객체를 프로토타입이라고 합니다. (개념상으로는 주로 두 번째로 해석되는 듯합니다.)

따라서 B의 프로토타입은 A라는 객체를 지칭하는 것이 됩니다.

 

3. __proto__ 는 무엇인가요?

지금 당장 인터넷 브라우저 개발자 콘솔 창을 켜서 아무 객체나 console.dir()로 안의 구조를 한번 보시길 바랍니다.

어떤 객체에도 다 있습니다. 1번에서 말한 Prototype 프로퍼티와 마찬가지로 말이죠. 그 이유는 이 __proto__ 프로퍼티는 사실 Prototype을 그대로 참조하는 녀석입니다. 그런데 왜 Prototype이 직접 있지 않고 왜 숨겨놓고 그것을 참조하는 __proto__를 만들었을까요? 그것에는 이유가 있지만 지금은 일단 이렇게 상황만 알아둡시다.

( 참고로 __proto__ 는 던더 프로토라고 읽습니다.)

 

4. 던더 프로토?

인터넷에서 프로토타입을 설명하는 코드를 보면, 직접 Prototype를 이용하지 않고 이 던더 프로토를 이용해서 보여줍니다. 그 이유는 Prototype으로 직접 하려면 초보자분들이? 보기에는 생소한 함수를 써야 하기 때문입니다. 그래서 일단 집중을 흐리지 않고 설명하기 위해 주로 던더 프로토를 이용해 설명하는 것으로 보입니다. 

원래 자바스크립트 공식에서는 이 던더 프로토의 사용을 지양하라고 하고 있습니다. 때문에 그냥 개념 파악에만 집중하시기 바랍니다. (그냥 "Prototype == 던더 프로토"라고 생각하시고 개념 이해에만 집중하시면 됩니다.)

 

5. 코드를 봅시다. 다음은 상속하는 과정, 프로토타입과 this의 성질을 모두 말해주는 간단한 코드입니다.

const A = {
  name : '나는 A야',
  func1(){
    console.log(this.name);		// 자기 name프로퍼티를 출력해보는 메서드
  }
}

const B = {
  name : '나는 B입니다.',
  __proto__ : A,				// A의 func1()자원을 쓰고 싶어서 상속받아봅니다.
}

A.func1();						// 나는 A야
B.func1();						// 나는 B입니다.

5-1. 프로토타입으로 상속

B에서 보면 던더 프로토에 A객체를 넣어줍니다. 그럼 B의 프로토타입은 A를 참조하게 됩니다. (그래서 결국 B의 프로토타입은 A가 됩니다.)

이렇게 되면 B에서는 비록 func1()를 정의해주지 않았지만 func1()이라는 자원을 상속받아 사용할 수 있습니다.

 

5-2. 프로토타입과 this

위를 잘 보시면 func1() 메서드에서 this.name 이 보이실 겁니다. 이놈의 자바스크립트에서 this는 초보 개발자들을 햇갈리하는 존재입니다. 상황에 따라서 this가 가리키는 객체가 달라지기 때문이죠. 

(나중에 이 this에 대해서도 포스팅 한 번 해보겠습니다.)

 

원래 위 코드에서 func1()를 호출하는 부분에서 생략을 하지 않고 제대로 쓰면 

B.func1() 이 아니라

B.__proto__. func1() 이 되어야 하죠? 맞습니다. 원래 풀로 적으면 이렇게 적어야 하죠 

func1()의. (점 연산자) 앞에 __proto__라는 프로퍼티이자 곧 A라는 객체를 가리키니깐 어떻게 생각해보면 "나는 A야"가 콘솔 창에 뜨는 게 맞다고 생각하실 수 있습니다. 

 

그러나 여기서 프로토타입의 특징이 나옵니다.

1. __proto__ 은 생략해서 쓸 수 있다. 

2. B의 프로토타입을 this로 가리키면 그 this는 B의 프로토타입인 A를 가리키는 것이 아니라, B본인을 가리킨다.

 

 

이상 프로토타입의 개념 설명이었습니다. 코드 부분도 이어서 포스팅하겠습니다.

 

 

 

 

 

 

 

*틀린 점이 있다면 댓글로 달아주세요. 아직 배우는 학생이랍니다.
*질문도 댓글로 적어주시면 답변할 수 있는 한도 내에서 답변해드리겠습니다.

 

반응형