---
title: JavaScript核心篇 - 原型鏈
tags:
description:
---
JavaScript核心篇 - 原型鏈
===
### 哪裡會看到原型
:::success
原型鍊的概念就是**向上查找**。
:::
#### 陣列
- 變數`arr`是一個陣列實體,prototype也就是原型,**原型具有向上查找的特性**。
- 所以找到==Array這個藍圖(陣列原型)==,所以也就可以使用`.forEach`這個方法。

```javascript=
const arr = [1, 2, 3, 4];
arr.forEach(item => console.log(item));
```

#### 類陣列
```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`。

---
<br>
### 額外增加原型方法
- `Array.prototype`可看到**陣列原型(藍圖)**。
```javascript=
console.log(Array.prototype);
```

#### 建立一個陣列方法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的實體`小白`、`小黃`都能使用到方法。

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

```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)的方法。

- `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()`==。
