본문 바로가기

JavaScript

[JavaScript] 프로토타입 (prototype)

프로토타입

자바스크립트는 프로토타입 기반 언어이다.

클래스 기반 언어에서는 '상속'을 사용하지만 프로토타입 기반 언어에서는 '어떤 객체를 원형으로 삼고 이를 복제함'으로써 상속과 비슷한 효과를 얻는다.

 

let instance = new Constructor

어떤 생성자 함수를 new연산자와 함께 호출하면 constructor에 정의된 내용을 바탕으로 새로운 인스턴스가 생성된다.

이때 instance에는 __proto__ 라는 프로퍼티가 자동으로 부여되는데 이 프로퍼티는 constructor의 prototype 이라는 프로퍼티는 참조한다.

 

어려운 말 말고 조금 더 쉬운 말로 바꿔보자..

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}
let 학생1 = new 기계();
let 학생2 = new 기계();

여기서 기계라는 함수 하나를 만들었는데 prototype이라는 항목이 생성된다. 간단하게 부모 자식으로 설명하고자 하면 기계.prototype은 기계의 유전자라고 생각하면 된다.

(console.log로 확인해 보면 뭔지 모르겠지만 출력되긴 한다.)

그래서 기계.prototype에 변수나 함수가 들어가 있다면 기계로 부터 생성된 학생1, 학생2는 전부 물려받아 쓸 수 있다.

function 기계(){
  this.name = 'Kim';
  this.age = 15;
}

기계.prototype.gender = '남';
let 학생1 = new 기계();
let 학생2 = new 기계();

console.log(학생1.gender); //'남' 출력

학생1, 학생2가 gender를 가지고 있지 않아도 학생1의 부모인 기계가 gender를 가지고 있어서 상속받아 갖게된다는 것이다.

 

왜 이렇게 되는걸까?

이게 자바스크립트의 특성이라 그렇다.. 자바스크립트는 오브젝트에서 데이터를 추출할 때 확인하는 순서가 있는데,

1. 학생1에 gender라는 값이 있는가?

2. 학생1의 부모에 gender라는 값이 있는가?

3. 부모의 부모에 gneder라는 값이 있는가?

...

이런식으로 자식의 부모 > 부모의 부모 를 타고간다고 생각하면 된다.

 

내장함수 toString()을 쓸 수 있는 이유?

자바스크립트 array, object에 붙일 수 있는 내장함수들이 많은데 이 이유는 뭘까..? 라고 생각이 들었는데,

let arr = [1,2,3];
let arr = new Array(1,2,3);

우리가 대괄호를 쳐서 만드는 배열이 컴퓨터 내부적으로는 new 키워드를 이용하여 array를 만들기 때문인데 이 new 키워드는 위에서 말했던 부모자식 관계와 똑같이 생겼다.

그래서 arr의 부모인 Array가 가지고 있는 많은 함수들(sort, push, map, forEach)을 arr가 쓸 수 있는 것이다.

 

부모의 유전자를 찾고 싶다면? __poroto__

부모로 부터 생성된 자식 object들은 __proto__라는 속성이 있다. 이걸 출력해 보면 부모의 prototype이 출력되는데 이 말은

자식.__proto__  와 부모.prototype이 같다는 말이다.  이렇게 계속계속 타고 가다 보면 모든 object 자료형은 조상은 Object()가 나오게 되며 (Object.prototype), 모든 array 자료형의 조상도 Object() 인걸 알 수 있다.

프로토타입 체인

프로토타입 체인은 어떤 데이터의 __proto__ 프로퍼티 내부에 다시 __proto__ 프로퍼티가 연쇄적으로 이어진 것이다. 이 체인을 따라가며 검색하는 것이 프로토타입 체이닝이다. 어떤 메서드를 호출하면 자신의 프로퍼티를 검색해서 메서드를 실행하고, 없으면 __proto__를 검색해서 실행하고 계속해서 검색하게 된다. 어쨌든 결국 최종보스는 Object.prototype인걸 알 수 있다.

Object.create() : ES5 문법

프로토타입 체인의 마지막 최종보스에는 Object.prototype이 있다고 했는데, 예외적으로 Object.create 이용하면 Object.prototype에 접근할 수 없으며, 이 방식을 쓰게되면 내장메서드&프로퍼티가 제거되어 객체 자체의 무게가 가벼워짐으로 성능상 이점을 가지게 된다.

 

마치며..

한 번에 이해하기 어려운 용어(prototype, __proto__, constructor, instance)를 사용하여 설명할 땐 잘 이해가 가지 않았는데, 쉬운 용어로 풀어 이해하다 보니 내가 왜 이런 코드를 짜야했는지 이해가 갔다. 지금까지는 근본을 모르고 무지성으로 코드를 짰다면 이제 그 안에 담긴 용어와 의미들을 생각하며 짜야겠다는 생각이 들었다.