본문 바로가기

Javascript

[자바스크립트] 프로토타입이란 무엇일까?

지난 글에서, 오브젝트 복사기계를 만드는 것이 class라고 말했다.(지난글을 읽지 않았다면 읽는것을 추천!)

그리고 그 안에 오브젝트의 여러가지 속성들을 미리 정의해둘 수 있다는 것을 배웠다. 


프로토타입으로 데이터 물려주기 : 

그런데, 프로토타입을 사용해도 자식 오브젝트에게 데이터를 물려줄 수 있다는 사실을 아는가? 

프로토타입은 기본적으로 '유전자'라는 개념을 가지고 있다. 우리의 생김새는 어떻게 결정되는가? 부모님이 우리에게 물려주신 유전자에 의해서 결정된다. 부모님의 유전자가 무엇이냐에 따라서 우리의 생김새가 달라진다. prototype도 마찬가지로 유전자라고 생각할 수 있다. 이 유전자의 값에 따라서 거기서 파생되는 자식들이 소유한 속성값이 달라진다. 지난번 헬스장등록기계로 다시 예를 들어 설명해보자.

등록기계.prototype.피티2회권 = true

이렇게 프로토타입에 추가하면 등록기계의 유전자에  피티2회권이라는 값이 추가된다. 

등록기계의 유전자에 값이 추가된 것이기 때문에, 이 기계로부터 나오는 인스턴스들에는 다 해당 값이 나오게 된다. 그러니까 헬스장에 등록한 사람들이면 전부다 피티2회권을 가지게 되는 것이다. 

 

이것이 상속을 하는 기능이다. 

function 등록기계() {
this.키 = 170;
this.몸무게 = 65;
}
//클래스를 선언할 때 선언된 속성은 자식만 값을 가지는 속성들

위의 코드를 보면 클래스를 생성할 때 속성을 쓰면 자식이 그 값을 직접 가지는데,

등록기계.prototype.피티2회권 = true

이렇게 프로토타입에 값을 쓰면 부모만 해당값을 가지게 된다. 


어떤 원리로 이렇게 되는 것일까?(프로토타입체이닝) :

console.log(철수)

이렇게 철수를 막상 출력하면 '피티2회권'이라는 값을 가지고 있지 않지만, 

철수.피티2회권 이라고 출력하면 true 라는 값이 나온다는 것을 확인할 수 있다.

 

var 철수 = new 등록기계()
철수.피티2회권

 

이렇게 값을 확인을 해볼 때, 만약 철수가 '피티2회권'을 가지고 있으면 그 값을 바로 출력해줄 것이다. 그런데 사실 철수가 직접 그 속성을 가지고 있는 것은 아니다. 하지만 값이 없어도 컴퓨터는 포기하지 않는다. 

자식에게서 '피티2회권'이라는 속성을 찾았는데 없다면 그 부모를 뒤진다. 부모의 유전자를 확인한다.

그런다음 부모에 값이 잇으면 부모로부터 값을 받아와서 출력한다. 이런 원리로 이루어지는 것이다. 

순서로 표현하면 다음과 같다. 

 

1.자식에게 직접 자료 있으면 그거 출력

2.없으면 부모유전자까지 뒤진다.

3.없으면 부모의 부모의 유전자까지 확인한다.

이것을 전문용어로 프로토타입체이닝이라고 한다. 


응용 - 배열에서 sort, length와 같은 메서드는 어떻게 사용할 수 있는 것일까? : 

var 어레이 = [4,2,1];
어레이.sort()

이런 코드를 우리는 자주 볼 수 있다.이렇듯 어레이에는 사용할 수 있는 기본 메서드들이 있다.

왜 이렇게 어레이의 함수들에서 이런 메서드를 사용할 수 있는 것일까? 그 이유가 무엇일까? 

자바스크립트에서 어레이 만들때 바로 [1,2,3] 과 같은 방식으로 어레이 값을 부여하는 방법도 있지만, 또 다른 방법도 있다. 

var 어레이 = new Array(4,2,1)

이렇게 우리는 배열을 선언할 수 있다. 그런데 여기까지 확인하면, 우리는 이 생긴 모양이 클래스가 자식 인스턴스를 생성하는 모양새와 굉장히 비슷하다는 것을 알 수 있다. 사실 그게 맞다. 

어레이라는 기계가 있는데, 그것으로부터 자식을 생산하고 있는 것이었다. 

'어레이'라는 변수는 Array라는 클래스로부터 파생된 인스턴스인 것이다. 

 

다시 생각해보자. 우리는 어레이.sort라는 메서드를 사용할 수 있었다. 

그 이유가 무엇일까? 

Array라는 부모가 그런 값들을 가지고 있기 때문이다. 

Array.prototype을 콘솔에서 출력해 확인해보면, 그 안에 여러가지 메서드값들이 들어있는 것을 알 수 있다. 이렇듯 Array의 프로토타입에 여러가지 메서드가 저장되어 있는 이유로 배열로 선언된 여러가지 변수들에서 우리는 Array가 가지고 있는 메서드들을 사용할 수 있는 것이다. 


또 다른 응용 :

예를 들어서 생각해보자. 배열에서 3을 삭제하는 기능을 만들고 싶다. 단순히 지금 선언한 배열 변수에서만 그것을 사용하고 싶은 것이 아니라, 앞으로 만들 모든 배열에 적용하고 싶은 것이다. 

그러면 

Array.prototype.삭제기능 = function(){}

이렇게 만들면 이제 모든 어레이에서 함수라는 메서드를 사용할 수 있게 될 것이다. 

 

let 안녕 = [1,2,3]
let hi = [1,2,3]

안녕.삭제기능
hi.삭제기능

위의 코드와 같이 모든 선언된 배열에서 이제부터 '삭제기능'이라는 메서드를 사용할 수 있게 되었다. 왜냐하면 Array의 유전자(prototype)에 삭제기능이 추가되었기 때문이다!