이전 글에서 이어지는 내용입니다.
이전 글의 핵심은
'인스턴스는 생성자 함수의 프로토타입과 연결됨'이었다.
과연 인스턴스는 생성자 함수의 프로토타입과 어떻게 연결될까?
이는 프로토타입 상속과 프로토타입 체인에 의해 설명된다.
아래 글을 모두 읽은 뒤 다시 보길 바란다.
프로토타입 상속(Prototypal inheritance)
이전 글의 코드를 다시 살펴보자.
const Animal = function(species, birthYear) {
this.species = species;
this.birthYear = birthYear;
}
Animal.prototype.calcAge = function () {
console.log(2022 - this.birthYear);
}
const tiger = new Animal('Siberian', 1234);
tiger.calcAge(); // 788
console.log(tiger); // Animal {species: 'Siberian', birthYear: 1234}
tiger 객체 내부를 자세히 살펴보면 [[Prototype]] 프로퍼티가 존재하며 그 안에 calcAge 메서드가 있음을 알 수 있다.
사실 new 연산자를 이용해 인스턴스를 생성하면 자동으로 인스턴스에 [[prototype]] 프로퍼티가 생성된다.
인스턴스 tiger의 [[prototype]]는 해당 생성자 함수의 prototype를 참조하므로 메서드를 사용할 수 있는 것이다
즉, 인스턴스 객체에는 해당 메서드가 없지만,
[[Prototype]]을 통해 생성자 함수의 프로토타입 내에 해당 메서드가 있는지 확인해 존재할 때 메서드가 실행된다.
또한, 인스턴스는 생성자 함수의 프로토타입으로부터 메서드를 상속('프로토타입 상속')받았다고 표현할 수 있다.
tiger.__proto__ === Animal.prototype // true
__proto__를 이용해 인스턴스의 [[Prototype]]에 접근할 수 있다.
프로토타입 체인(Prototype chain)
각 객체에 존재하는 [[Prototype]] 프로퍼티를 이용해 상위 프로토타입에 도달할 수 있다.
const num = [1, 2, 3];
console.log(num.map((v) => v * 2)); // [2, 4, 6]
위 코드에서 생성자 함수가 보이지 않지만,
객체 리터럴[]로 생성된 배열은 new Array 생성자 함수로 배열을 생성한 것과 같다고 할 수 있다.
그래서 인스턴스 num은 Array의 프로토타입에 저장된 map과 같은 배열과 관련된 메서드를 사용할 수 있는 것이다.
console.log(num.__proto__ === Array.prototype); // true
위 코드에서 인스턴스의 [[Prototype]]으로 Array의 프로토타입에 도달할 수 있음을 알 수 있다.
또 다른 코드를 보자.
console.log(num.hasOwnProperty(1)); // true
console.log(num.__proto__); // [constructor: ƒ, at: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, …]
console.log(num.__proto__.__proto__); // Object.prototype
첫 줄 코드를 보면, 배열의 인스턴스인 num에 hasOwnProperty 메서드를 정상적으로 호출되었다.
하지만 배열 인스턴스의 상위 프로토타입인 Array.prototype(num.__proto__)에는 hasOwnProperty라는 메서드를 찾아볼 수 없다.
어떻게 프로토타입에 존재하지 않는 메서드를 실행할 수 있을까?
프로토타입도 객체이며 모든 객체는 프로토타입을 갖기 때문에
인스턴스가 가리키는 프로토타입 프로퍼티만 탐색하지 않기 때문이다.
hasOwnProperty 메서드는 Object.prototype에서 찾을 수 있어 정상적으로 호출되는데
이는 다음의 과정을 거치기 때문이다.
인스턴스 num에서의 [[Prototype]] 프로퍼티에 방문하여 해당 메서드를 찾고 만약 없다면
num.__proto__의 [[Prototype]] 프로퍼티 내부에 해당 메서드가 있는지 확인한다.
이는 프로토타입도 내부에 프로토타입을 갖기 때문에 연쇄적으로 탐색할 수 있는 것이다.
이렇게 어떤 데이터의 [[Prototype]] 프로퍼티 내부에 다시 [[Prototype]] 프로퍼티가 연쇄적으로 이어지며, 이 체인을 따라가며 검색하는 것을 ‘프로토타입 체이닝(prototype chaining)’이라고 한다.
프로토타입 체이닝을 통해 도달할 수 있는 최상위 객체는 Object이며 Object.prototype은 null을 가리킨다.
또한, DOM 요소들도 객체이며 이 또한 프로토타입을 갖고 프로토타입 체인을 갖는다.
자바스크립트는 프로토타입 기반의 언어이며,
프로토타입 또한 객체이며 모든 객체는 프로토타입을 갖는다.
위 한 줄이 프로토타입을 이해하는데에 가장 중요하다.
'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) 이해하기 1 (0) | 2022.07.13 |