- 코어 자바스크립트를 읽고, 프로토타입에 대해 공부한 내용을 정리한다.
프로토타입(Prototype)
: 자바스크립트의 모든 객체와 연결된, 부모 역할을 담당하는 객체.
- JS에는 클래스 기반이 아닌, 프로토타입 기반 객체 지향 언어이다.
- 프로토타입을 통해 객체 지향의 상속 개념을 구현한다.
프로토타입의 개념
다음과 같은 코드가 있을 때, 이 코드를 실행한 결과를 도식화 하면 아래와 같은 그림을 그릴 수 있다.
const instance = new Foo();
- Foo 생성자 함수를 통해 Foo의 인스턴스인 instance를 생성하고 있다.
- 이 때, instance의 __proto__([[prototype]]) 프로퍼티가 자동으로 부여되고, 이 프로퍼티는 해당 인스턴스의 부모의 프로퍼티(여기서는 Foo의 prototype)를 가리킨다.
__proto__ 와 [[prototype]]
- ES5 명세에는 __proto__가 아닌, [[prototype]]으로 정의되어있음.
- 본래 __proto__는 브라우저가 [[prototype]]을 구현한 것.
- 프로토타입에 접근하기 위해서는 instance.__proto__를 사용할 수 있으나, 이는 권장되지 않고 Object.getPrototypeOf() 등을 활용하는 것이 권장됨.
__proto__ & prototype
둘 다 프로토타입 객체를 가리키지만, 같은 것은 아니다.
- __proto__ 는 객체 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리킨다.
- prototype 객체는 함수만 갖는다(즉, 위의 instance는 prototype을 갖고 있지 않다!).
- 이 함수가 생성자로 사용될 때, 이 함수로 생성된 객체의 __proto__가 가리키는 대상이 된다.
- 이 함수로 만들어진 인스턴스가 사용할 수 있는 메서드가 저장되어 있다.
prototype에 지정한 메서드는 해당 함수로 만들어진 인스턴스들이 접근할 수 있게 된다.
class Foo {
constructor (bar) {
this.bar = bar;
}
};
Foo.prototype.getBar = function () {
return this.bar;
};
const instance = new Foo('Hello');
console.log(instance.getBar()); // instance의 bar에 저장된 Hello가 출력된다.
- 위에서 instance가 getBar 함수를 호출할 수 있는 이유는, instance의 __proto__가 Foo의 prototype을 참조하기 때문이다.
- 하지만, getBar 함수를 호출할 때 __proto__를 사용하지 않고도 호출할 수 있음을 알 수 있다.
- 이는 JS에서 __proto__가 생략 가능한 프로퍼티이기 때문이다!
- 따라서 인스턴스는, 자신의 생성자 함수의 prototype에 지정된 프로퍼티나 메서드를 자신의 것처럼 접근할 수 있다.
const arr = new Array(3);
console.dir(arr);
console.dir(Array);
위의 코드를 실행하면 아래와 같은 결과를 얻을 수 있다.
- Array 생성자로 생성한 배열 arr의 [[Prototype]] (__proto__)에 생성자 함수인 Array가 들어가 있다.
- 생성자 함수 Array를 출력한 결과를 보면, prototype 프로퍼티 내부에 push, shift 등의 함수가 들어가 있다. 이는 arr의 __proto__와 동일한 내용이다.
- 따라서 생성자 함수로 만들어진 인스턴스는, 자신의 __proto__를 통해 생성자 함수의 prototype을 참조할 수 있으며, 이를 호출할 때는 __proto__를 생략할 수 있으므로 인스턴스의 메서드인 것 처럼 사용할 수 있다.
- 그러나 생성자 함수의 prototype에 포함되어 있지 않은 메서드는 다른 메서드는 인스턴스가 호출할 수 없다.
→ ex) Array 생성자의 isArray() 등의 메서드는 arr.isArray() 같은 형태로 사용이 불가능하다.
Constructor 프로퍼티
: __proto__와 prototype 두 객체의 내부에 존재하는 프로퍼티. 원래의 생성자 함수(자기 자신)를 참조한다.
- 인스턴스의 원형을 알 수 있는 수단으로 기능한다.
- constructor가 가리키는 대상은 변경이 가능하다.
- 다만, 변경한다고 해서 해당 인스턴스의 원형이나 타입이 변하지는 않는다(아래 코드 참조).
class Foo {
constructor (bar) {
this.bar = bar;
}
};
const NewFoo = function () {
console.log('New foo');
};
Foo.prototype.getBar = function () {
return this.bar;
};
var instance = new Foo('Hello');
instance.constructor = NewFoo;
console.log(instance instanceof NewFoo); // false
console.log(instance.constructor.name); // NewFoo
- 처음 프로토타입 개념을 공부하기 시작했을 때, 이해가 힘들어서 한참 허우적댔다(...) __proto__와 prototype의 차이를 깨닫는데 특히 시간이 걸렸던.
- 다음 글에서는 프로토타입 체인에 대해 공부할 예정.
'공부 > JS' 카테고리의 다른 글
함수형 자바스크립트 훑어보기 (0) | 2024.11.26 |
---|---|
[Javascript] 프로토타입 알아보기 - 2 (0) | 2024.02.02 |
[Javascript] 콜백 함수 알아보기 (1) | 2024.01.21 |
[Javascript] 클로저 알아보기 - 2 (1) | 2024.01.08 |
[Javascript] 클로저 알아보기 - 1 (1) | 2024.01.05 |