Web Front-end/JavaScript

[JS/객체/프로토타입] JS의 프로토타입

JavaScript는 프로토타입형 객체지향 언어이기도 하고, 함수형으로 쓸 수도 있고, 뭐 다양한 측면을 가진 언어입니다.

(non-blocking , single-Thread,concurrency ,asynchronized 언어이기도 하죠) 자바스크립트의 빼놓을 수 없는 특징 중 하나인, 프토로타입에 대해서 적어봅시다!

프로토타입

현실에서 "프로토타입" 이라는 말 많이 쓸 일이 없지만 , 프로토타입에 대해서 먼저 알아봅시다. 종종 영화같은데나 게임버전 같은데서는 Prototype이라는 용어를 씁니다. 아이언맨에서 "프로토타입"이라는 말이 나오는데요 , 구글링을 해보겠습니다.

검색결과

아이언맨 1에 나오는 초기 슈트입니다!  감은 잡힙니다. "프로토타입"이라고 하면, 뭔가 초기버전 , 근본이 되는 1.0ver같은 그런 느낌이 들긴합니다. 하지만, Iron man의 가장 매력적인 점은 따뜻한 마음도 있지만, 다양한 슈트가 있다는 점입니다.

즉, 프로토타입에서 다른 버전으로 업그레이드 하면서,  다른 특성들을 가지게 되지만 , 우리가 생각하는 "아이언맨"의 원형은 크게 바뀌지 않죠. 즉, 누구나 생각하면 딱 떠오르는 "아이언맨"이라는 원형은 크게 변하지 않습니다.(머리에 씌워져있고, 눈은 빛나면서 가슴 중간에는 토니의 상징인 아크 원자로가 있고, 손과 발에 있는 부스터를 이용해 비행을 하는 등)

 

프로토타입은 바로 이겁니다. 누구나 생각하는 "이상적인 원형" ,"이상적인 형태"라고 할 수 있습니다. 예를 더 들어볼게요. 대부분 물고기를 그려보라고 하면, 아가미에 , 꼬리는 v자 형태에, 유선형으로 그립니다. 새를 그려보라고 하면, 날개가 있고, 다리가 2개고, 발가락이 3개인 형태를 그립니다.  

 

TMI (글쓴이의 주접)

더보기

이 점에서, JAVA의 class와 다른점이 드러나게 되죠. JAVA는 "특징"들을 정의해놓고(class선언), 틀에서 찍어내게 객체를 정의합니다. 그래서 , JAVA에서는 완벽한 Class를 설계하는 것은 정말 어렵습니다. 이와 다르게, JS에서 객체를 바라보는 시선은 , 이상적인 형태인 각각의 Prototype이 있으며, 그걸 확장시키는 개념인거죠.

 

사실 이 개념은 언어 설계자가 어떤 철학을 가지고 개발했냐에 달렸는것이기 때문에, 객체에 대한 시선은 충분히 사람마다 각자 해석하는 것이 다를 수 있습니다. 단지 , JS의 개발 철학은 Prototype에 기반을 두고 있다는 이야기를 하는 것입니다! 프로토타입에 대한 더 정확한 의미는 "Eleanor Rosch"의 "프로토 타입이론"에서 프로토타입에 대한 정의가 나옵니다.

JS에서 프로토타입

JS는 내부적으로 객체,함수,배열 등의 Prototype(Function.Prototype,Object.Prototype와 같은)을 갖고 있습니다. 그리고, 프로그래머가 사용하는 객체들에게 Prototype에 정의되어있는 constructor로 생성하게한 뒤, 자신의 정보를 [[Prototype]]객체로 묶어서 넣어주게 됩니다. 코드로 봅시다.

const arr= [1,2,3,4,5]
const obj = {
	name:"hello",
}

console.dir(arr)
console.dir(obj)

정리하면, 이렇게 말을 할 수 있습니다.결국, 쉽게 이야기하면 아래처럼 이야기할 수 있습니다. 

JS에서 Prototype은 객체(함수든, array든,object든)를 생성할 때, 부모객체를 프로토 타입이라고 합니다. 

ECMA Scrip Spec(공식문서)에서는 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯 (interal slot)을 가지고, [[Prototype]]의 값은 null 또는 객체이며 , 상속을 구현하는데 사용된다고 안내하고 있습니다.

  • Prototype은 특정 객체를 생성할 때, 부모객체를 "Prototype"이라고 할 수 있다. (O)
  • [[Prototype]]를 부모를 통해 받기 때문에, "상속"이라는 개념을 구현 할 수 있다. (O)

여러분 , 조금 만 더 깊게 들어가봅시다. 이거 재밌더라구요! 앞으로, 함수,배열, 객체들을 모두 지칭할 때는 큰 Object, 자바스크립트에서 리터럴로 생성하는 객체를 말할 때는 작은 object라고 쓸겁니다!. 

JS 객체 생성방법

JS에서 객체를 생성하는 방법은 여러가지가 있습니다. 객체 리터럴, 생성자 함수이용,Object.create가 있습니다. 이 3가지가 묘하게 다른거 아시나요! 왜 이렇게 다양하게 있을까요. 한가지만 있으면 될텐데 말이죠.

 

함수도 Object 이고 , object도 Object이고, 배열도 Object 입니다. 그럼, 특별한 친구가 있죠. "생성자"라는 친구입니다. 생성자라는 친구는 함수이면서, 어떠한 객체(object)를 "생성"하는 친구입니다. 즉, Function.Prototype을 갖고 있으면서, 특정 객체(object)를 생성될 객체(object)한테 가르쳐 줘야합니다. 그래서,함수 타입에는 prototype이라는 property가 있습니다. 이걸 설명하는 이유는 , prototype property와 ~~.prototype이 무지무지 헷갈리기 때문입니다.

function a(){
}
console.dir(a)

prototype

객체 리터럴로 객체 생성하기

 

JS로 객체를 생성할 때, 가장 흔하게 쓰는 방법 중 하나인 객체 리터럴입니다. 객체 리터럴의 생성과정을 prototype을 적용해서 생각을 해보도록 하겠습니다.

const obj= {
	name:"Mapin",
    say:"hello!",

}

프로토 타입관점에서 위의 객체 리터럴을 이용하는 생성과정은 아래와 같은 Prototype Chain이 형성됩니다.

생성된 객체의 prototype이 Object.prototype으로, "객체 프로토타입"이 자신의 부모가 되죠.

생성자를 이용하는 방법은 어떻게 될까요?

function Obj(name,say){
	this.name=name;
    this.say=say;
    this.sayHello = function(){
    	console.log(`Hello! Im ${this.name} ${this.say}`)
    }
}

const ob = new Obj("mapin","Yob");

프로토 타입관점에서 위의 생성자 함수를 이용하는 생성과정은 아래와 같은 Prototype Chain이 형성됩니다.

생성된 객체의 prototype이 Obj.prototype으로, 자신을 생성한 부모가 자신의 프로토 타입이 되는것이죠.

3줄요약

  • JS에서 객체를 바라보는 관점은 Prototype이다.
  • Prototype은 객체가 생성 되었을 때, 자신의 부모객체를 가리킨다. [[prototype]]객체를 주입받아, "상속"이라는 개념을 이용할 수 있게 된다.
  • 객체를 생성하는 방법에 따라서, prototype chain이 바뀐다.

 

refer

프로토타입 deepdive