프로토타입을 이해하기 위해서는 ES6 클래스 개념이 등장하기 이전, 클래스라는 개념 없이 객체를 생성할 수 있었던 생성자 함수의 이해가 필요하다.
생성자 함수(Constructor functions)
다른 언어의 클래스 개념을 생성자 함수를 통해 구현할 수 있으며 생성자 함수는 다음 조건을 충족해야 한다.
- 항상 함수명의 첫 글자는 대문자여야 한다.
- 화살표 함수가 아닌 선언문 함수나 표현문 함수로 작성되어야 한다. 화살표 함수는 자신만의 this를 가지지 않기 때문이다.
- new 연산자로 생성자 함수를 호출해야 한다.
prototype을 이해하기 위해서는 this라는 개념이 필요하다. this를 복습하고 읽는 것을 추천드린다.
'use strict';
const Animal = function(species) {
console.log(this); // Animal {}
}
new Animal('Siberian');
⭐ new 연산자를 이용해 생성자 함수를 호출하면 다음의 과정을 거친다.
1. 빈 객체{}가 생성된다.
2. 함수가 호출될 때 this는 생성된 빈 객체{}를 가리킨다.
3. 빈 객체는 생성자 함수의 프로토타입과 연결된다.
4. 마지막으로 자동으로 생성자 함수는 this(객체)를 반환한다.
3번이 이해가 가지 않더라도 일단은 넘어가자.
'use strict';
const Animal = function(species, birthYear) {
this.species = species;
this.birthYear = birthYear;
// this.calcAge = function() {...}
}
const tiger = new Animal('Siberian', 1234);
console.log(tiger); // Animal {species: 'Siberian', birthYear: 1234}
console.log(tiger instanceof Animal); // true
new 연산자를 이용해 생성자 함수인 Animal를 호출한 결과,
Animal 함수로부터 생성된 빈 객체에 species와 birthYear이라는 프로퍼티가 추가되어 tiger라는 변수에 할당되었다.
(new 연산자로 생성자 함수를 호출하면 객체를 반환하기 때문이다.)
즉, 변수 tiger는 Animal 함수로부터 생성된 인스턴스이다.
위 예시에서 보듯 Animal 함수 내부에 필드 프로퍼티는 작성했지만 메서드는 작성하지 않았다.
아니 작성하지 않는 것이 좋다.
만약 함수 내부에 메서드를 작성하면 모든 인스턴스에 사용할지도 모르는 메서드가 항상 포함되므로 비효율적인 코드가 되기 때문이다.
그럼 어떻게 다른 언어처럼 클래스 내부의 메서드를 구현할 수 있을까?
여기서 프로토타입이 필요하다.
Animal.prototype.calcAge = function () {
console.log(2022 - this.birthYear);
}
console.log(Animal.prototype); // {calcAge: ƒ, constructor: ƒ}
tiger.calcAge(); // 788
console.log(tiger); // Animal {species: 'Siberian', birthYear: 1234}
생성자 함수에 프로토타입을 이용해 calcAge라는 메서드를 생성했으며 인스턴스를 이용해 메서드를 호출하였다.
Animal.prototype에는 calcAge 메서드가 생성되어 있음을 확인할 수 있다.
또한, 인스턴스 tiger로 Animal의 프로토타입의 calcAge 메서드를 정상적으로 호출함을 확인할 수 있다.
하지만 tiger 객체를 출력해보니 calcAge 메서드가 존재하지 않는다.
이 부분이 가장 중요하다.
인스턴스 tiger 내부에 calcAge 메서드가 존재하지 않는데
어떻게 인스턴스를 이용해 메서드가 정상적으로 호출될 수 있었을까?
이 문제의 답은 위 생성자 호출 과정 3번 문항에서 찾아볼 수 있다.
인스턴스는 생성자 함수의 프로토타입과 연결되기 때문이다.
즉, Animal 함수로 생성된 인스턴스는 Animal.prototype에 저장된 메서드를 사용할 수 있다.
다시 말해 인스턴스는 생성자 함수의 프로토타입을 참조한다.
사실 프로토타입을 배우지 않았어도 한 번쯤은 자바스크립트 문법을 검색하면서 접해봤을 것이다.
자바스크립트를 처음 접했다면 굉장히 궁금했을 것이다. 왜 map() 앞에 Array.prototype이 붙는걸까? 과연 무슨 뜻일까?
오늘 배운 개념을 토대로 Array.prototype.map()을 대략적으로 설명할 수 있겠다.
Array 함수의 프로토타입에는 map()을 포함한 배열과 관련된 모든 메서드를 갖고 있으며 배열 객체를 통해 해당 메서드를 사용할 수 있음을 의미한다.
다음 글은 프로토타입 체이닝에 대해 다뤄보려 한다.
'Javascript' 카테고리의 다른 글
SessionStorage를 이용해 캐시 구현하기 (0) | 2022.11.23 |
---|---|
[JS] DocumentFragment, Template tag (0) | 2022.10.26 |
[JS] 클로저(Closures) 이해하기 (0) | 2022.10.18 |
spread와 rest 비교하기 (0) | 2022.07.28 |
프로토타입(Prototype) 이해하기 2 (0) | 2022.07.17 |