자바스크립트의 모든 객체는 자신의 부모역할을 담당하는 객체와 연결되어 있다.
그리고 이것은 부모객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다.
이러한 부모객체를 Prototype객체 또는 prototype이라고 한다.
prototype객체는 생성자 함수에 의해 생성된 공유프로퍼티를 제공하기 위해 사용한다.
자바스크립트의 모든 객체는 [prototype]이라는 인터널 슬롯을 가진다.
[[prototype]]의 값은 null 또는 객체이며 상속을 구현하는 데 사용된다. [[prototype]]객체의 데이터 프로퍼티는 get 액세스를ㄹ 위해 상속되어 자식객체의 프로퍼티처럼 사용할 수 있다. 하지만 set액세스는 허용되지 않는다.
student 객체는 proto_프로퍼티로 자신의 부모객체 (프로토타입 객체)인 Object.prototype을 가리키고 있다.
var student = {
name : 'Lee',
score : 90
}
console.log(student.__proto__ === Object.prototype) // true```
### 2. [[prototype]] 과 prototype 프로퍼티의 비교
모든 객체는 자신의 프로토타입 객체를 가리키는 [[Prototype]] 인터널 슬롯(internal slot) 을 갖으며 상속을 위해 사용된다.
함수도 객체이므로 [[Prototype]] 인터널 슬롯을 갖는다. 그런데 함수 객체는 일반 객체와는 달리 prototype 프로퍼티도 소유하게 된다.
```javascript
function Person(name) {
this.name = name;
}
var foo = new Person('Lee');
console.dir(Person); // prototype 프로퍼티가 있다.
console.dif(Person); // prototype 프로퍼티가 없다.```
- [[prototype]]
- 함수를 포함함 모든객체가 가지고 있는 인터넷 슬롯
- 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체을 가리킴, 함수객체의 경우 Function.prototype을 가리킴
- prototype 프로퍼티
- **함수 객체만 가지고 있는 프로퍼티**이다.
- 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모역할을 하는 객체(프로토타입 객체)를 가리킨다.
### 3. constructor 프로퍼티
- 프로토타입 객체는 constructor 프로퍼티를 갖는다.
- constructor 프로퍼티는 객체의 입장에서 자신을 생성한 객체를 가리킨다.
```javascript
//객체
var student = {
name : 'Lee'
}
// 생성자 함수를 이용해 만든 객체
function Person(name){
this.name = name;
}
var aPerson = new Person('Kim');
// 확인
console.dir(student.constructor) // Object 생성자 함수
console.dir(aPerson.constructor) // Person 생성자 함수```
### 4. Prototype Chain
자바스크립트는 특정객체의 프로퍼티나 메소드에 접근하려 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[prorotype]]이 가리키는 링크를 따라 자신의 부모역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색한다. 이 것을 **프로토 체인**이라 한다.
```javascript
function Car(model){
this.model = model;
}
Car.prototype.color = 'red';
var car1 = new Car('sonata');
car1.style = 'sports';
console.log(car1) // Car {model: "sonata", style: "sports"}
console.log(car1.style); // 'style' (car1 객체의 프로퍼티)
console.log(car1.color); // 'red' (car1의 상위객체 car1.__proto__.color 프로퍼티)```
### 객체 생성 방법
- 객체 리터럴
- 생성자 함수
- Obect() 생성자 함수
```javascript
// 객체 리터럴, Object생성자 함수(객체리터럴로 생성하면 엔진 내부적으로 Object생성자 함수로 객체만듬)
var literal = {name : Chanho};
//생성자 함수
function Literal(name) {
this.name = name;
}
var makeName = new Literal('Jisung');```
### 생성자함수로 생성된 객체의 프로토타입체인
생성자 함수로 객체를 생성하기 위해서는 우선 생성자 함수를 정의하여야 한다.
**함수를 정의하는 방식**
- 함수표현식(Function declaration)
- 함수선언식(Function expression)
- Function() 생성자 함수
3가지 함수 정의 방식은 결국 Function() 생성자 함수를 통해 함수 객체를 생성한다, 따라서 어떠한 방식으로 함수 객체를 생성하여도 **모든 함수 객체의 prototype 객체는 Function.prototype**이다.
생성자 함수도 함수 객체이므로 생성자 함수의 prototype 객체는 Function.prototype이다.
### 프로토타입 객체의 확장
프로토타입 객체도 객체이므로 일반 객체와 같이 프로퍼티를 추가/삭제할 수 있다. 그리고 이렇게 추가/삭제된 프로퍼티는 즉시프로토타입 체인에 반영된다.
```javascript
function Person(name) {
this.name = name;
}
var foo = new Person('Lee');
Person.prototype.sayHello = function(){
console.log('Hi! my name is ' + this.name);
};
foo.sayHello(); // Hi! my name is Lee```
### 프로토타입 객체의 변경
객체를 생성할 때 프로토타입은 결정된다. **결정된 프로토타입 객체는 다른 임의의 객체로 변경할 수 있다.** 이것은 부모 객체인 프로토타입을 동적으로 변경할 수 있다는 것을 의미한다. 이러한 특징을 활용하여 객체의 상속을 구현할 수 있다.
!!!!!!!!!!!!이때 주의할 것은 프로토타입 객체를 변경하면!!!!!!!!!!!!
- **프로토타입 객체 변경 시점 이전에 생성된 객체**
- 기존 프로토타입 객체를 [[Prototype]]에 바인딩한다.
- **프로토타입 객체 변경 시점 이후에 생성된 객체**
- 변경된 프로토타입 객체를 [[Prototype]]에 바인딩한다.
```javascript
function Person(name) {
this.name = name;
}
var foo = new Person('Lee');
// 프로토타입 객체의 변경
Person.prototype = { gender: 'male' };
var bar = new Person('Kim');
console.log(foo.gender); // undefined
console.log(bar.gender); // 'male'
console.log(foo.constructor); // ① Person(name)
console.log(bar.constructor); // ② Object()```