[코어JS] 6. 프로토타입(prototype) - 하

1. prototype, [[Prototype]], constructor


생성자함수가 있을 때 new연산자로 인스턴스를 만들면, constructor의 prototype이라는 프로퍼티의 내용이 [[Prototype]]라고 하는 프로퍼티로 참조를 전달하게 됨. 즉, Constructor.prototype와 instance[[Prototype]]가 같은 객체를 바라봄.

[[Prototype]]는 접근가능한 것이 아니라 정보를 보여주기만 하기 뿐이므로 실제 동작상으로는 instance와 동일시됨.

리터럴로 생성하든, Array 생성자함수로 생성하든, 내부구조는 모두 Array 생성자함수로 생성한 것과 동일하게 동작함. 생성자로 생성하게 되면 생성자 함수는 Array이고, Array함수에는 여러가지 프로퍼티들이 있음. 이 중 'prototype'이라는 프로퍼티가 있는데, 이것이 배열 리터럴의 [[Prototype]]로 연결되어있음. 그리고 이 prototype프로퍼티는 객체인데, 안에는 배열 메서드들이 담겨있음. 이것을 도식화 한 것이 직각삼각형 그림임.

배열 인스턴스를 출력하고, [[Prototype]]을 열어보면 Array.prototype의 내용과 같은 것을 확인할 수 있음.


prototype내부에 constructor이라는 프로퍼티가 있는데 여기에 Array함수가 담겨있음. 즉, Array.prototype.constructor에는 생성자함수 자기자신(Array)가 담겨있음.

배열.constructor역시 똑같이 배열의 생성자함수를 가리킴.

[1, 2, 3].constructor로 접근하려고하면, [1, 2, 3].[[Prototype]].constructor와 같은 요청으로 인식할 것이고, 이는 Array.prototype.constructor와 동일하다고 간주함. 그리고 이들은 다시 Array함수를 가리키게 됨.

(실제 [1, 2, 3].[[Prototype]].constructor의 코드로 접근은 불가하지만 내부적으로 동작하는 모습을 표현한 것)

배열에 대해서는 Array 생성자함수와 그 프로토타입으로 이루어져있는데, 프로토타입에는 배열에 관련된 메서드들이 모두 들어있는 것.

숫자리터럴은 객체가 아니기 때문에 [[Prototype]]프로퍼티가 없음. 하지만 리터럴을 인스턴스인 것 처럼 사용하려고 하면(메서드 사용) JS가 임시로 숫자 리터럴에 해당하는 number생성자함수의 인스턴스를 만들어서 그 프로토타입에 있는 메서드를 적용해서 원하는 결과를 얻은 후 인스턴스를 제거하는 식으로 동작.

문자열도 마찬가지로 메서드를 호출하는 순간 임시로 문자열의 인스턴스를 만들어 그 메서드를 실행하고 결과를 얻음과 동시에 인스턴스를 폐기함.

기본형 데이터의 경우 인스턴스 폐기 과정을 거치지만, 참조형 데이터의 경우 처음부터 인스턴스기 때문에 폐기과정이 없음.

어쨌거나 숫자형, 문자열, 배열, 함수 등등 모두 메서드에 접근하려고 할 때 직각삼각형 구조가 됨. 데이터 자신에게는 메서드들이 없지만, 생성자함수의 prototype 프로퍼티에 있는 것을 [[Prototype]]라는 연결통로에 의해서 자신의 것 처럼 사용할 수 있음. null과 undefined를 제외한 모든 데이터타입은 이와같은 생성자함수가 존재하고, 각 생성자함수의 프로토타입에는 각 데이터타입에만 해당하는 전용 메서드들이 정의가 되어있음.


앞서 봤듯이 [[Prototype]]는 콘솔에만 확인될 뿐 실존하지는 않음. 인스턴스로부터 prototype 프로퍼티에 직접 접근하려면 instance.__proto__Object.getPrototypeOf(instance)를 사용. instance.__proto__는 콘솔에서 확인되지는 않으나 접근가능함. 하지만 ES2015에서 호환성을 위해 만들어진 방법이라 공식적인 방법 Object.getPrototypeOf(instance)를 사용하는 것을 권장.

위 코드의 roy와 royClone1~4는 모두 Person의 인스턴스가 됨. 모두 동일한 프로퍼티에 접근할 수 있음.

instance.__proto__
instance.
Object.getPrototypeOf(instance)
Constructor.prototype

네가지 방식을 통해 생성자함수의 prototype이라는 프로퍼티에 접근가능

Constructor
instance.__proto__.constructor
instance.constructor
(Object.getPrototypeOf(instance)).constructor
Constructor.prototype.constructor

다섯가지 모두 생성자함수를 가리키고, 다섯가지 방법으로 생성자함수에 접근가능함.

2. 메서드 상속 및 동작원리


Person생성자로부터 두 개의 인스턴스 roy, jay를 만들고 각각 setOlder, getAge메서드를 만들음. 반복이 발생함.

프로토타입으로 메서드를 옮김으로써 반복을 줄일 수 있음.

여러개의 인스턴스를 만들어도 한번 지정한 코드를 참조하게 됨. 인스턴스들은 각각 고유한 정보들만 가지고 있으면 되고, 인스턴스들이 모두 똑같이 가지는 정보들은 prototype로 보내면 됨. 그럼에도 각 인스턴스들은 마치 자신의 메서드인 것처럼 prototype의 정보를 사용할 수 있음.

이를 통해 메모리용량 최적화가 가능하고, 객체지향적 관점에서 어떤 객체가 속한 집단의 특징을 알 쑤 있는 좋은 수단이 되기도 함.(특정 집단의 공통된 속성 파악 : 사람의 나이를 알 수 있고 모두 나이를 먹음)

3. 프로토타입 체이닝(Prototype Chaining)


앞서 일반화시킨 내용에서 prototype 프로퍼티 역시 객체였음. 즉, prototype 프로퍼티 객체 역시 Object생성자 함수의 new연산으로 성성된 인스턴스임. 따라서 Object의 prototype와 연결되어있음. 인스턴스는 Object.prototype에 있는 메서드도 자신의 것 처럼 사용할 수 있음. 이와같이 붉은 대각선을 따라 연결되어있는 프로토타입들을 프로토타입 체인이라고 함. 프로토타입은 모두 객체이므로, 모든 데이터타입은 한결같이 이와 동일한 구조를 따름.

모든 데이터타입에 대해 [[Prototype]]로 연결된 Object.prototype에는 자바스크립트 전체를 통괄하는 공통된 메서드들이 정의되어 있음.(hasOwnProperty, toString, valueOf, isPrototype 등) 이들 메서드는 모든 데이터 타입이 프로토타입 체이닝을 통해 접근할 수 있음.


프로토타입 체이닝으로 인해 객체 전용 메서드들은 프로토타입에 정의되어있지 않음. 객체의 프로토타입에 있는 메서드는 모든 데이터 타입에 적용되기 때문에, 다른 데이터 타입에서 사용되어 에러를 발생시킬 수 있음. 이에 Object.prototype에 정의하는 것을 포기하고 객체 생성자함수에 직접 메서드가 정의되어있음. 객체에 관련된 명령어들은 객체로부터 직접 메서드를 호출하지 않고, Object.명령어를 호출하면서 매개변수로 객체자신을 넘겨주는 방식을 취하는 이유임.


[1, 2, 3].toString()을 실행하면 배열 요소들을 컴마로 나열한 "1,2,3"이 출력됨. Array.prototype.toStringdelete하고 [1, 2, 3].toString()을 실행하면 "[object Array]"가 출력됨. Object.prototypetoString메서드가 있어 프로토타입 체인에 의해 이것이 호출된 것. call 메서드로 직접 실행하면 같은 결과가 나오는 것으로 확인가능. Object.prototype.toString마저 delete[1, 2, 3].toString()를 실행하면 그제서야 toString메서드를 찾지 못하겠다는 오류를 던짐.

이를 통해, 메서드를 호출하면 메서드를 인스턴스 자기자신에서 먼저 찾고, 없으면 Array.prototype에서 찾고, 없으면 Object.prototype에서 찾음. 중간과정에서 있으면 호출하고, 없으면 에러를 던짐. 즉, 가장 먼저 발견된 메서드를 실행. 스코프체인과 개념이 같음.(가장 가까운 자기자신부터 찾고, 가장 먼저 찾아진 것만 실행하고, 더 멀리있는 체인까지 찾진 않음)

4. 정리


1. 인스턴스에는 메서드가 없음에도 불구하고 [[Prototype]]라는 매개체 덕분에 생성자함수의 prototype에 있는 메서드를 자신의 것 처럼 사용할 수 있음.
2. [[Prototype]]으로 이어진 각 prototype들에 모두 접근할 수 있는 것을 프로토타입 체인이라고 함.
[[Prototype]] : 그림에서 빨간 점선

좋은 웹페이지 즐겨찾기