programming language/javascript

Prototype이란?

공대키메라 2021. 9. 2. 21:47

Prototype 이란 뭘까?

 

우선 영어 사전을 검색해 보자 .

 

검색해 본 결과 원형이라는 말이다.

 

어떤 원형인지 그것을 이제부터 같이 알아갈 것이다. 

 

생성자 함수가 있을 때 new 연산자로 인스턴스를 만들게 되면 

 

그 인스턴스에는 constructor의 prototype이라고 하는 프로퍼티의 내용이 Prototype이라고 하는 프로퍼티로 참조를 전달하게 된다.  

 

이게 무슨말이냐면

 

Constructor.prototype이랑 instance[[Prototype]]가 곧 같은 객체를 바라본다는 말이다. 

 

그런데... [[Prototype]]는 접근가능한 것이 아니라 정보를 보여주기만 할 뿐으로, 실제 동작상으로는 instance와 동일시가 된다.  그래서 밑의 그림처럼 삼각형이 된다. 

 

 

그래서 이게 어쨋다는 건지는 차근차근 알아가보도록 하자. 

 

배열이 있다고 하자. 

 

[1, 2, 3] <= 리터럴로 생성한 배열이든, Array 생성자 함수로 생성한 배열이든, 내부 구조는 모두 Array 생성자 함수로 생성한 것과 동일하게 동작한다. 

 

생성자로 생성한 경우에는  생성자 함수는 Array이고 이 Array라고 하는 함수에는 여러 프로퍼티들이 있다. 

 

from(), isArray(), of(), arguments, length, name, prototype 

 

이중에 우리가 공부하고 있는 prototype이라고 하는 프로퍼티가 있다. 

 

이것이 배열 리터럴의 [[Prototype]]로 연결이 되어 있는 것이다. 

 

그리고 이 prototype이라고 하는 프로퍼티는 객체인데, 이 객체에는 또 여러개가 담겨있다. 

 

이것을 그림으로 보이면...

 

 

이렇게 나타난다. 

 

이것을 간단하게 도식화 하면 처음이 보여준 그림이 나온다. 

 

짜잔~

 

이번에는 배열 인스턴스를 출력해보겠다. 

 

console.dir([1, 2, 3]);을 하면... 

 

이런 식으로 나오게 된다. 

 

근데 자세히 보면

prototype안에 constructor가 있는데 이곳에 다시 Array가 담겨 있다. 

 

이런 식으로 같은것이 담기는것을 확인할 수 가 있다. 

 

동일!

 

Array뿐만 아니라 다른 것들도(Number, String, Function)도 시험해 보면 같은 결과가 나온다. 

 

그 것이 어떤것이 되었든 메서드에 접근하고자 할 땐 전부 이런 구조가 된다. 

 

데이터 자신에게는 메소드들이 없지만, 생성자 함수의 prototype 프로퍼티에 있는 것을 [[Prototype]]라는 연결통로에 의해서 마치 자신의 것처럼 쓸 수 있다는 것이다!

 

null과 undefined를 제외한 모든 데이터 타입은 위처럼 생성자 함수가 존재하고, 각 생성자 함수의 프로토타입에는 각 데이터타입에만 해당하는 전용 메소드들이 정의가 되어 있다는 것이다!

 

다시 전의 그림으로 돌아가서... 

 

[[Prototype]]은 콘솔에 표시되는 내용일 뿐이고 실제로 이 프로퍼티를 이용해서 prorotype에 직접 접근할 수 는 없다. 

 

instance로 부터 prototype 프로퍼티에 직접 접근할 수 있는 방법은 없을까?

 

2가지의 방법이 있다. 

 

  1. instance.__proto__
  2. Object.getPrototypeOf(instance)

1번째 접근법은 ES2015에서 기존 브라우저들이 마음대로 제공하고 있는 기능을 호환성 차원에서 하는 수 없이 문서화해 준 것일 뿐이기 때문에 가급적이면 공식적인 방법인 2번째 방법을 사용하라고 한다. 

 

그러면 이것을 이용해서 다시 한번 코드를 봐보자 

function Person(n, a){
	this.name = n;
    this.age = a;
}

var roy = new Person('로이', 30);

var royClone1 = new roy.__proto__.constructor('로이_클론',10);

var royClone2 = roy.constructor('로이_클론2',25);

var royClone3 = new Object.getPrototypeOf(roy).constructor('로이 클론3',10);

var royClone4 = new Person.prototype.constructor('로이_클론4', 15);

위에서 생성자 함수의 prototype이라고 하는 프로퍼티에 접근하기 위해 

 

밑에 처럼 구현한 것이다. 

또한 이것들 모두 동일한 함수 Person이라고 하는 생성자 함수를 가리킨다. 

 

Person 생성자로부터 roy객체, 그리고 jay라고 하는 객체, 총 2개의 인스턴스를 만들엇다. 

 

function Person(n, a){
	this.name = n;
    this.age = a;
}

var roy = new Person('로이', 30);
var jay = new Person('제이', 25);

roy.setOlder = function(){
	this.age += 1;
}

roy.getAge = function(){
	return this.age;
}

jay.setOlder = function(){
	this.age += 1;
}

jay.getAge = function(){
	return this.age;
}

위를 DRY한 코드로 바꿔보자 (Don't Repeat Yourself!)

 

function Person(n, a){
	this.name = n;
    this.age = a;
}

Person.prototype.setOlder = function(){
	this.age += 1; 
}

Person.prototype.getAge = function(){
	return this.age;
}

var roy = new Person('로이', 30);
var jay = new Person('제이', 25);

 

프로토타입으로 메소드를 이동시켰다. 

 

이렇게하면 얻는 이점은 뭘까?

마구 도장찍듯이 찍어내도 크게 문제가 없단다!

 

이 메소드들은 딱 한번만 만들어 놓은 코드를 여기저기서 참조할 뿐이다. 

 

인스턴스들은 저마다의 고유한 정보들만 가지고 있으면 되고 

 

인스턴스들이 모두 똑같이 가지는 정보들을 prototype으로 보내면 된다.

 

=> 메모시리 사용 효율을 상당히 끌어올릴 수가 있다!

 

뿐만아니라, 객체지향적 관점에서 보면 개개인의 이름, 나이 등의 특징은 다 다르지만, 

 

"사람은 모두 나이를 먹고, 각자의 나이를 알 수 있다" 라고 하는 일반화된 특징들을 모두 prototype으로 설명할 수 있는것이다!

 

다름 그림을 그럼 보자. 

 

 

prototype 프로퍼티 역시 객체이다. 

 

그러니까 protytype 프로퍼티 역시 object 생성자 함수의 new 연산으로 생성된 인스턴스라는 말이 된다. 

 

따러서 object의 prototype과 연결이 되어 있다.  

 

그러면 인스턴스는 Object.prototype에 있는 메서드도 마치 자신의 것처럼 사용이 가능하다. 

 

여기서 대각선의 빨간선을 따라서 연결되어 있는 프로토타입들을 일컬어 Prototype Chain이라고 부른다. 

 

 모든 데이터는 위 그림처럼 똑같은 구조를 같는다. 즉, 모두 Object.prototype과 프로토타입 체인으로 연결되어 있다. 

 

 

객체 프로포타입 메소드는 모든 곳에서 그래서 접근이 가능하다고 한다. 

 

instance에는 메서드가 없음애도 불구하고 [[prototype]]이라는 매개체 덕분에 생성자 함수의 prototype이라는 메소드를 마치 자신의 것처럼 쓸수가 있다. 

 

빨간 점선처럼 [[Prototyupe]]으로 이어진 각 prototype들에 모두 접근할 수 있는 것을 일컬어 프로토 타입 체인이라고 한다. 

 

mdn사이트에도 이에 대해 잘 설명을 하고 있으니 이것도 보면 좋을 것 같다. 

 

https://developer.mozilla.org/ko/docs/Web/JavaScript/Inheritance_and_the_prototype_chain

 

상속과 프로토타입 - JavaScript | MDN

Java 나 C++ 같이 클래스 기반의 언어를 사용하던 프로그래머는 자바스크립트가 동적인 언어라는 점과 클래스가 없다는 것에서 혼란스러워 한다. (ES2015부터 class 키워드를 지원하기 시작했으나,

developer.mozilla.org

 

'programming language > javascript' 카테고리의 다른 글

Let vs Var? 무엇을 써야 할까?  (4) 2021.09.03
Async vs Defer 는?  (2) 2021.09.02
Closure란?  (0) 2021.09.01
Callback Fucntion 이란?  (0) 2021.09.01
This란?  (0) 2021.09.01