---
# System prepended metadata

title: JavaScript核心篇 - 原型鏈

---

---
title: JavaScript核心篇 - 原型鏈
tags: 
description:
---

JavaScript核心篇 - 原型鏈
===

### 哪裡會看到原型

:::success
原型鍊的概念就是**向上查找**。
:::

#### 陣列
- 變數`arr`是一個陣列實體，prototype也就是原型，**原型具有向上查找的特性**。
- 所以找到==Array這個藍圖（陣列原型）==，所以也就可以使用`.forEach`這個方法。

  ![](https://i.imgur.com/w1JsiNJ.png =40%x)

    ```javascript=
    const arr = [1, 2, 3, 4];
    arr.forEach(item => console.log(item));
    ```
    ![](https://i.imgur.com/qz74phT.png =30%x)
    

#### 類陣列

```htmlmixed=
<ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
</ul>
```
- 選取所有的`<li>`標籤。
- `console.dir(li)`用**dir**可以看到所有的值。
```javascript=
const li = document.querySelectorAll('li');
console.dir(li);
```
- prototype是`NodeList`，表示是==由`NodeList`建立的實體==。

- 從prototype看到的方法就是可以使用的。

- 再往上查找可以找到`prototype：Object`。

![](https://i.imgur.com/lFODvpj.png =50%x)

---
<br>

### 額外增加原型方法

- `Array.prototype`可看到**陣列原型（藍圖）**。
```javascript=
console.log(Array.prototype);
```
![](https://i.imgur.com/fYQblB9.png =70%x)

#### 建立一個陣列方法getLast（回傳陣列最後一個值）

- 在`Array.prototype`增加一個方法`.getLast`，後面要**加上傳統函式**。
  :point_right: 一般函式無法透過**new**建立實體
  
- `this`指的是**陣列本身**。
- 把陣列的最後一個`index`回傳**return**出來。
- 最後**return**的值是`5`。
```javascript=
const arr = [1, 2, 3, 4, 5];

Array.prototype.getLast = function () {
  return this[this.length - 1];
};

console.log(arr.getLast());
```

---
<br>

### 原型鍊關鍵點

原型方法，會套用在所有的物件上。
- 省記憶體
- 好管理


---
<br>

### 函式建構子

以**狗(Dog)**作為例子，使用藍圖(**函式建構子**)來創造**狗**。 :point_right: 建構子名稱開頭要**大寫**

如何規劃藍圖(**函式建構子**)
1. **定義固有屬性（實體）**：毛色、名字。 :point_right: 會**佔用**記憶體。

2. **定義方法（共用）**：走、叫。 :point_right: 會**共用**記憶體方法。

<br>

- 現在建立一個變數`小白`，賦予藍圖，成為**實體**。
```javascript=
function Dog(color, name) {

};  // 藍圖（函式建構子）

const 小白 = new Dog(); // 實體

console.log(Dog); // 藍圖
console.log(小白);  // 實體
```

- 定義**屬性**，color: `白色`、name: `小白`。
- 再另外建立一個變數`小黃`，賦予藍圖，成為**實體**。分別定義**屬性**，color: `黃色`、name: `小黃`。
```javascript=
const 小白 = new Dog('白色', '小白'); // 實體
console.log(小白);

const 小黃 = new Dog('黃色', '小黃'); // 實體
console.log(小黃);
```

- 建立**共用**方法就會從**prototype原型**裡去加。這樣兩個Dog的實體`小白`、`小黃`都能使用到方法。

![](https://i.imgur.com/dgpKg0n.png =50%x)

- 在**Dog**加入`walk`的方法。
- 兩個實體`小白`、`小黃`都能共用到方法`walk()`。

![](https://i.imgur.com/x539q8e.png =45%x)

```javascript=
Dog.prototype.walk = function () {
  console.log(`${this.name}會走路`);
};

const 小白 = new Dog('白色', '小白'); // 實體
console.log(小白);

const 小黑 = new Dog('黑色', '小黑'); // 實體
console.log(小黑);

小白.walk();    // 小白會走路
小白.bark();    // 小白會吠叫
小黑.walk();    // 小黑會走路
小黑.bark();    // 小黑會吠叫
```
---
<br>

### class語法糖
用class的方式來規劃**藍圖（函式建構子）**，建立共用方法。

```javascript=
class Dog {
  constructor(color, name) {
    this.color = color;
    this.name = name;
  }
  walk() {
    console.log(`${this.name}會走路`);
  }
  bark() {
    console.log(`${this.name}會吠叫`);
  }
};
```
- 與**閉包不同**的是，`constructor(){}`內部的this可被**外部取用**。

  例如：
    ```javascript=
    const pow = new Dog('黑白色','賤狗');

    console.log(pow.color);    // 黑白色
    console.log(pow.name);    // 賤狗
    ```    
---
<br>

### 函式建構子的原型繼承

- `Dog`會吠叫，`Cat`會喵喵叫，所以`Dog`與`Cat`兩個完全不同的藍圖。

- 不過`Dog`與`Cat`都會走路，所以要去繼承更頂層的藍圖（Animal）的方法。


![](https://i.imgur.com/TGpkS99.png =80%x)

- `Dog`與`Cat`分別都有各自的方法`bark()`、`meow()`。

```javascript=
class Dog {
  constructor(color, name) {
    this.color = color;
    this.name = name;
  }
  bark() {
    console.log(`${this.name}會吠叫`);
  }
};
class Cat {
  constructor(color, name) {
    this.color = color;
    this.name = name;
  }
  meow () {
    console.log(`${this.name}會喵喵叫`);
  }
}

const 小白 = new Dog('白色', '小白'); // 實體
console.log(小白);

const 小黑 = new Dog('黑色', '小黑'); // 實體
console.log(小黑);

const 小花 = new Cat('花色', '小花'); // 實體
console.log(小花);

```
- 現在`Dog`與`Cat`都要去繼承`Animal`的方法`walk()`。
```javascript=
class Animal {
  constructor(type) {
    this.type = type || '都是人';
  }
  walk() {
    console.log(`${this.name}會走路`);
  }
};
```
- `class Cat`改成`class Cat extends Animal`，基於`Animal`而拓增的原型`Cat`。

- `constructor`裡面加上==super(``'貓'``)==，這是要傳到`Animal`的`constructor(type)`去==建立固有屬性==。

```javascript=
class Cat extends Animal {
  constructor(color, name) {
    super('貓');
    this.color = color;
    this.name = name;
  }
  meow () {
    console.log(`${this.name}會喵喵叫`);
  }
}
```

- 看到`Cat`的原型，多了`type: ‘貓’`。

- `prototype`的第一層 `constructior: class Cat`，第二層 `constructior: class Animal`。

- 現在`Cat`的原型，能夠==使用`Animal`的方法`walk()`==。

  ![](https://i.imgur.com/2dMpy1V.png =70%x)
  

