자바스크립트는 흔히 프로토타입 기반 언어라 불린다. 모든 객체들이 메소드와 프로퍼티를 상속 받기 위해서 프로토타입 객체를 가진다는 의미다. prototype객체도 prototype을 갖고 상위의 프로토타입 객체도 마찬가지다. 이를 프로토타입 체인이라고 한다. 이에 대해 알아보고자 한다.
생성자 함수를 new
키워드를 통해 생성하면 인스턴스가 생성된다. 인스턴스는 [[prototype]]
내부 속성을 갖는데 이는 생성자 함수의 prototype
프로퍼티를 참조하고 있다. (복사 아니고 참조다)
프로토타입은 위와 같은 형식으로 생성자를 생성한다. 이 과정이 Java에서는 class로 인스턴스를 생성하는 것과 같은 기능을 하는 것이다.
💡 __proto__
__proto__ 는 legacy로 남아있다. 대신에Object.getPrototypeOf(obj)
를 통해 접근해야 한다.
function Person(first, last, age, gender, interests) {
// 속성과 메소드 정의
this.first = first;
this.last = last;
//...
}
Person.prototype.getName = function() {
return this.first;
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
console.dir(person1)
console.dir(Person)
console.log(Object.getPrototypeOf(person1) === Person.prototype); // true
console.log(person1.getName()) // Bob
Person
생성자 함수의 prototype
프로퍼티와 인스턴스 person1
의 [[prototype]]
같은 객체를 가르키고 있다. 아래 이미지는 위 코드의 콘솔이다. 빨간색으로 표시된 부분이 같은 객체이다.Person.prototype.getName
의 정의가 person1
인스턴스의 [[Prototype]]
에 존재하여 인스턴스가 직접 접근 가능하다.이처럼 생성자의 prototype
은 상속시킬 프로퍼티나 메소드를 보관하는 장소가 된다.
위 이미지를 보면 prototype에 constructor
를 가지고 있다. 이는 생성자 함수 자기 자신을 가르키고 있다. 직접 constructor
를 이용해 접근도 가능하다. 이 프로퍼티는 자신의 원형을 알기 위한 속성이다.
person1.constructor
person2.constructor
또한, 다음과 같이 constructor
프로퍼티를 통해 새로운 인스턴스를 생성하는 것도 가능하다.
var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
console.log(person3.first, person3.last);
객체의 생성자를 확인하기 위해
constructor.name
을 사용하지 말자constructor.name
은 변경 가능하기 때문이다.instanceof
를 사용하자
프로토타입 체인은 상속을 구현할 수 있는 방식이다. 이에 더해, 내적 동질성을 구현하기 위한 장치로도 사용된다.
위 코드에서 Person의 [[Prototype]]
안에 또 다시 [[Prototype]]
가 있다. 해당 객체는 [[Prototype]]
에 존재하는 프로퍼티나 메소드에 접근 가능하다. 아래 코드를 보면,
person1.valueof(); // OK
해당 코드는 정상적으로 작동하고 출력 된다. 그 과정은 이렇다.
valueof
메소드가 있는지 확인한다.[[Prototype]]
를 따라 올라가 valueof
가 있는지 확인한다.[[Prototype]]
안에 [[Prototype]]
을 타고 올라가 valueof
가 있는지 확인한다. prototype
에 존재하는 valueof
메소드를 실행한다.person1.valueof = function() {
console.log('hi');
}
person1.valueof(); // hi
만약 위 코드처럼 person1에 직접 valueof
메소드를 구현한다면 우선적으로 hi가 출력 된다.
정리하자면 프로토타입 체인은 자신의 메소드가 있다면 먼저 사용하게 되고(내적 동질성), 없다면 prototype을 타고 올라가서 찾기 때문에 상속을 가능하게 한다.