# Prototype 原型、Prototype Chain 原型鍊、Prototype Inheritance 原型繼承
## Prototype(原型), Prototype Chain (原型鍊)
### `__proto__`
> 讓我們 access 一個物件的 prototype
*(記得 prototype 實際上也是一個 object)*
:::info
所有的 object 都有 `__proto__` 這個 property
:::
*一個 object (物件) 裡面,除了所給予的 property (屬性值) 外,另外也包含 prototype (原型)。*
***
### JS 中任何東西的 prototype 到最後都是物件(除了原始型別)
::: warning
**Everything is an object** (or primitive)
:::
<img src="https://i.imgur.com/gFUA8ep.png" width="500px">
#### object 物件
```javascript
const a = {};
```
<img src="https://i.imgur.com/ZccqkGu.png" width="300px">
<br >
#### function 函式
```javascript
const b = function(){};
```
<img src="https://i.imgur.com/TdR4QjI.png" width="250px">
![]()
<img src="https://i.imgur.com/BCzDBH5.png" width="300px">
#### array 陣列
```javascript
const c = [];
```
<img src="https://i.imgur.com/QvSx4he.png" width="250px">
<img src="https://i.imgur.com/zAFeEvl.png" width="250px">
<img src="https://i.imgur.com/oCLMzXS.png" width="300px">
***
### 補充:primitive type 原始型別
> #### NOT AN OBJECT
> A type of data that represent a **single value**
| primitive type |
| -------- |
| String |
|Number|
|Boolean|
|`undefined`|
|`null`|
|BigInt|
|Symbol|
### MDN :point_down:

***
### Prototype Chain (原型鍊)
當我們在一個 Object 上 access 一個 property/method 時 ,如果在該 Object 上找不到,JavaScript Engine 就會查看該 Object 的 prototype(另一個 object),找不到再查看這個 prototype 的 prototype(再另一個 object)... 就這樣一直找下去,直到找到 property/method,或是到達了原型鏈(prototype chain)的終點。
<img src="https://i.imgur.com/Vydwlm4.png" width="500px">
*我們不需要做 `obj.__proto__.__proto__.prop3`, JS Engine 因為有 prototype chain 的行為,`obj.prop3`能直接用幫我們找到*
> #### JS Engine 這個沿著 prototype 一路往上查找的行為,就是 prototype chain。
<br >
***
## Building Objects
:::success
> ### 用 prototype 建立物件的三種方式
- **Function Constructors**
- **Classes**
- **`Object.create()`**
:::
#### 複習:function constructors & `new`
```javascript=
function Person(firstName, lastName){
console.log(this);
this.firstName = firstName;
this.lastName = lastName;
console.log('This function is invoked')
}
const john = new Person('John', 'Doe');
console.log(john);
// Person {}
// This function is invoked
// Person {firstName: "John", lastName: "Doe"}
```
<img src="https://i.imgur.com/v9F0Sek.png" width="600px">
<br >
### `.prototype`
> #### function 這種 object 的內建 property (屬性)
> 用來設定由這個 function constructor 建立的 object 的 prototype
<img src="https://i.imgur.com/pe5xY4V.png" width="500px">
:::warning
- 與 `__proto__` 是完全不同的東西
- `.prototype` 不是這個 function 的 prototype
- **只有一個 function 被當做 function constructor,透過 `new` 這個關鍵字來執行這個 function 時,function 的 `.prototype` 才有意義**
:::
<img src="https://i.imgur.com/ZSdlWLi.png" width="800px">
因為 Prototype Chain 的概念,所以我們可以用 `.prototype` 這樣的方式去設定由 function constructor 建立的 object 的 method
```javascript=
function Person(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
Person.prototype.getFullName = function(){
return this.firstName + ' ' + this.lastName;
}
Person.prototype.getFormalFullName = function(){
return this.firstName + ', ' + this.lastName;
}
const john = new Person('John', 'Doe');
const jane = new Person('Jane', 'Doe');
console.log(john.getFullName()); // John Doe
console.log(jane.getFormalFullName()); // Jane, Doe
```
<br >
***
### `Object.create()`
> #### Pure Prototypal Inheritance 最單純的原型繼承
```javascript=
const person = {
firstName: 'Default',
lastName: 'Default',
greet: function () {
return `Hi, ${this.firstName} ${this.lastName}`;
}
}
const john = Object.create(person);
console.log(john);
```
**注意`this` 的使用**
:::info
透過 `Object.create()` 可以
1. 建立一個 empty object 空物件
2. 將帶入 `Object.create()` 的參數內容,變成該物件的prototype 原型。
:::
<img src="https://i.imgur.com/H2PGhcp.png" width="500px">
![]()
:point_up: 產生一個空物件
<br >
<img src="https://i.imgur.com/vBR2v1C.png" width="400px">
:point_up: prototype 指向傳入 `Object.create()` 的參數
<br >
#### 用 `Object.create()` 製造 object
```javascript=
const person = {
firstName: 'Default',
lastName: 'Default',
greet: function () {
return `Hi, ${this.firstName} ${this.lastName}`;
}
}
const john = Object.create(person);
john.firstName = 'John';
console.log(john.greet()); // Hi, John Default
```
> 基於 **prototype chain** 的觀念
> overwrite 作為 prototype 的 object (base object) 的 property
對於 `firstName` 來說,在該物件就已經有這個屬性,因此它不會在往該物件的 prototype (原型) 去尋找,而對 `greet` 與`lastName` 來說,因為在 `john` 這個物件裡沒有這個 method 與這個 property,於是就會到 prototype 裡面去找
*這個方法更接近 JavaScript 的 prototype inheritance 運作原理,**所有的 prototype 也都是 object**,由 object 來繼承 object*