자바스크립트의 상속은 프로토타입을 구현한다고 했다.
누구로부터 무엇을 상속받았는지 확인하려면 나의 부모(의 부모의 부모 ….)를 계속해서 찾아나갈 수 있어야 하는데 부모 즉, 프로토타입을 찾아나가는 방법은 어떻게 구현되어 있을까?
식별자를 스코프 체인에서 찾는 것처럼, 자바스크립트 엔진은 프로토타입 체인
에서 프로퍼티와 메서드를 검색한다.
즉, 프로토타입 체인
은 상속
과 프로퍼티 검색
의 메커니즘이다.
다음과 같이 Animal 생성자 함수가 있다.
function Animal(species, sound) {
this.species = species;
this.sound = sound;
Animal.prototype.getAnimalSound = function () {
return this.sound;
};
}
Animal 생성자 함수로 객체를 생성하면, 그 객체는 species
와 sound
를 자신의 프로퍼티로 갖게 된다.
const dog = new Animal('dog', 'woof');
이때 dog
는 getAnimalSound
를 소유하고 있진 않지만 호출할 수 있다. 그 이유는 Animal.prototype
을 상속받았기 때문이다.
이렇게 자바스크립트는 객체의 프로퍼티나 메서드에 접근하려할 때 해당 객체(dog)에 접근하려는 프로퍼티
(getAnimalSound)가 없다면 [[Prototype]] 내부 슬롯
의 참조를 따라 자신의 부모 역할을 하는 프로토타입
(Animal.prototype)의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인
이라 한다.
이때 dog
가 hasOwnProperty
메서드를 소유하지 않지만 호출할 수 있는 이유도 동일한 이유다.
dog
의 프로토타입 체인을 그림으로 표현하면 다음과 같다.
위 그림을 바탕으로, 자바스크립트 엔진이 hasOwnProperty
메서드를 찾는 과정은 다음과 같다.
결론적으로, 자바스크립트의 상속의 메커니즘은 프로토타입 체인이다.
프로토타입 체인의 최상위에 위치하는 객체는 언제나 Object.prototype
이다. 따라서 모든 객체는 Object.prototype
을 상속받는다.
Object.prototype은 프로토타입 체인의 종점이다.
그럼 이 최상위 객체의 프로토타입은 무엇일까?
__proto__
접근자로 Object.prototype의 프로토타입
(부모 객체)을 조회해봤더니 null
이 나왔다.
Object.prototype의 내부 슬롯 [[Prototype]]은 null이다.
자바스크립트의 배열은 객체라는 것을 알고 있다. 객체이기 때문에 배열에도 프로퍼티와 메서드를 정의해줄 수 있다.
우리는 배열을 선언할 때 push, pop, map, filter, reduce 등의 메서드를 함께 선언해주지 않았지만 메서드를 호출해 사용할 수 있었다. 그 이유는 바로 우리가 아무렇지 않게 선언했던 배열은 Array.prototype
을 프로토타입(부모 객체)로 갖기 때문이다.
mdn 문서
에서 메서드를 검색하면 항상 붙어있던 Array.prototype
의 정체가 바로 배열 객체가 상속받을 프로토타입이었던 것!
mdn 문서
를 보면 모든 프로퍼티와 메서드가 prototype
으로 표기되어 있는 것은 아니다.
이렇게 Array.prototype에 정의되어 있지 않고 Array 자신만 소유하고 있는 프로퍼티/메서드를 정적 프로퍼티/메서드
라 한다. 정적 프로퍼티/메서드
는 생성자 함수로 인스턴스를 생성하지 않아도 참조/호출할 수 있다.
생성자 함수가 생성한 인스턴스는 자신의 프로토타입 체인에 속한 객체의 프로퍼티에 접근할 수 있었으나, 정적 프로퍼티는 인스턴스의 프로토타입 체인에 속한 객체의 프로퍼티가 아니므로 인스턴스로 정적 프로퍼티를 참조하거나 호출할 수 없다.
따라서 해당 프로퍼티를 소유하고 있는 대상(Array, Object 등)만 정적 프로퍼티를 참조하거나 호출할 수 있다.