---
# System prepended metadata

title: Prototype 原型、Prototype Chain 原型鍊、Prototype Inheritance 原型繼承

---

# 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: 
![](https://i.imgur.com/0h2Qo7r.png)

***
### 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*
