Javascript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용합니다.
JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라 불립니다. — 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다.
프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다.
이를 프로토타입 체인(prototype chain) 이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 합니다.
생성자 함수 정의(클래스)
function Person(first, last, age, gender, interests) {
// 속성과 메소드 정의
this.first = first;
this.last = last;
//...
}
인스턴스
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
person1의 프로토타입 객체인 Person()에 정의된 멤버들 name, age, gender, interests, bio, greeting을 볼 수 있습니다. 또한 — watch, valueOf처럼 Person()의 프로토타입 객체인 Object에 정의된 다른 멤버들도 보실 수 있습니다. 이는 프로토타입 체인이 동작한다는 증거입니다.
즉, person1은 부모인 Person의 속성들을 가져다 쓸 수 있고 Person은 부모인 Object의 속성들을 가져다 쓸 수 있습니다.
그렇다면 Object에 정의된 메소드를 person1에서 호출하면 어떻게 될까요?
person1.valueOf()
결과값
prototye: Object라는 것을 통해 valueOf()메소드는 Object에서 썻다는 것을 알 수 있습니다.
Note: 특정 객체의 프로토타입 객체에 바로 접근하는 공식적인 방법은 없습니다. 하지만 __proto__(en-US).(앞뒤로 언더바 2개씩)속성을 통해 특정 객체의 프로토타입 객체에 접근할 수 있도록 구현했습니다.
- ECMAScript 2015부터는 Object.getPrototypeOf(obj) 함수를 통해 객체의 프로토타입 객체에 바로 접근할 수 있게 되었습니다..
person1.__proto__
결과값
*__proto__.__proto__예시
person1.__proto__.__proto__
결과값
Object.prototype은 무엇을 뜻하는 걸까요?
위의 valueOf가 Object의 메소드입니다.
그러므로 valueOf는 Object.prototype이라고 할 수 있습니다.
즉, 객체에 속해있는 메소드, 속성등이 여기에 포함됩니다.
create()는 주어진 객체를 프로토타입 객체로 삼아 새로운 객체를 생성합니다.
var person2 = Object.create(person1);
person1을 프로토타입 객체로 지정했으므로 person2.__proto__는 person1이 됩니다.
모든 생성자 함수(클래스)는 constructor 속성을 지닌 객체를 프로토타입 객체로 가지고 있습니다.
constructor 속성은 원본 생성자 함수 자신을 가리키고 있습니다.
위의 예시에서 Person.prototype속성에 정의된 속성들은 Person() 생성자로 생성된 모든 인스턴스에서 사용할 수 있습니다.
그러므로 person1과 person2에도 constructor속성에 접근할 수 있습니다.
person1.constructor
person2.constructor
이를통해 person1.constructor는 결국 Person을 가리킴으로 이렇게 만들수도 있습니다.
var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
Object.prototype.name을 통해 프로토타입을 수정할 수 있습니다.
function Person(first, last, age, gender, interests) {
this.first = first;
this.last = last;
this.age = age;
this.gender = gender;
this.interests = interests;
}
const person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
Person.prototype.farewell = function() {
alert(this.first + ' has left the building. Bye for now!');
};
맨 밑에 생성자 Person에 prototype을 이용해 메소드를 추가해주었습니다.
person1.farewell();
//expected result: 'Bob has left the building.'
그러나 Person.prototype.farewell이 person1보다 밑에 있어 늦게 실행되는데도 실행이 잘 되는 이유는 무엇일까요?
프로토타입 객체는 모든 인스턴스에서 공유하기 때문에 정의하는 즉시 별도의 갱신과정 없이 접근이 가능하기 때문입니다.