---
tags: Javascript
---
# JS原型鍊(Prototype Chain)
物件擁有自己的屬性,他可以繼承原型,而原型也可以繼承其他原型,原先的物件可以使用`.`取用屬性,而如果在原本物件找不到此屬性,他就會向上查找直到找到屬性或是`null`(找到null就會報錯),而如果有從一個原型新增出兩個實體,他們會共用同一個原型的方法

## 特性
1. 一樣具有物件特性
1. 向上查找
1. 原型可共用發方法及屬性
## 原型在哪裡
**以下寫法為非正規寫法**
以下範例可以看到陣列的原型,也可以為他的原型加上屬性,因為屬性是共用的,假如你新增其他陣列也可以使用`getLast()`方法。

## 建構式自定義原型
利用函式建構物件,使用`Prototype`製作原型功能,在過去無規範如何製作原型功能,所以大多採用`__proto__`製作,後來`ECMAScript` 規範要使用`[[Prototype]]`製作原型功能,
但之前開發者大多使用`__proto__`原型所以瀏覽器還保留此方法,所以如果現在看到`[[Prototype]]`就是瀏覽器還沒更新前的`__proto__`是往上追朔的原型。
**`proto` 不屬於正規 `JS`,他是瀏覽器的方法,會導致同層所有資料被賦予新方法**
**`prototype` 是正規的`JS`方法,在為建構函式新增方法時、原型作多層串接時都會使用**
以下範例使用函式建構物件
```javascript=
// 利用含有 name 與 city 屬性的 human 函式,建立一個 Joe 物件:
function human(name, city) {
this.name = name;
this.city = city;
}
var Joe = new human('joe', 'Tiawan');
// 接著針對 human 函式的原型添加屬性
human.prototype.work = function() {
console.log(`${this.name}工作`);
}
console.log(Joe.work()); // joe工作
// __proto__ 物件上新增(維護難)
// prototype 函式上新增(建議在原型屬性上新增)
console.log(human.prototype === Joe.__proto__); // true
```
## Object.create 建立多層繼承
使用`Object.create`繼承方法,
當繼承函式執行時,`this` 值指向繼承的物件,而不是在函式內擁有屬性的原型物件。
[為啥總要修正constructor。](https://segmentfault.com/a/1190000016147953)補充
```javascript=
function Animal(family) {
this.kingdom = '動物界';
this.family = family;
}
Animal.prototype.move = function(){
console.log(`${this.name}走路`);
}
function Cat(name, color, size) {
Animal.call(this, '貓科'); // 只繼承原型,所以需補上建構函式
this.name = name;
this.color = color;
this.size = size;
}
Cat.prototype = Object.create(Animal.prototype); // 將Animal.prototype當作原型使用
Cat.prototype.constructor = Cat; // 將Cat建構函式補回去,否的話constructor會是Animal建構函式
Cat.prototype.detail = function(){
console.log(`名子:${this.name}, 顏色:${this.color}, 大小: ${this.size}`);
}
var Amy = new Cat('艾米', '棕色', '小型');
var Kumo = new Cat('哭某', '白色', '大型');
Amy.detail(); // 名子:艾米, 顏色:棕色, 大小: 小型
Amy.move(); // 艾米走路
Kumo.detail(); // 名子:哭某, 顏色:白色, 大小: 大型
Kumo.move(); // 哭某走路
```
## 使用ES6新語法 class建立物件
將上述的繼承與建立物件改成使用class語法,類別的主體指的是被大括號({})包含的部分,你可以在這裡面定義類別成員(members),例如方法(methods)或建構子(constructors)。
**若在子類別中有建構子(constructor),要使用this前則必須先呼叫super()函式。**
[class MDN](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Classes)
```javascript=
class Animal{
constructor(family) {
this.kingdom = '動物界';
this.family = family;
}
echoFamily() {
console.log(`${this.name}走路`);
}
}
class Cat extends Animal {
constructor(name, color, size) {
super('貓科');
this.name = name;
this.color = color;
this.size = size;
}
detail(){
console.log(`名子:${this.name}, 顏色:${this.color}, 大小: ${this.size}`);
}
}
var Amy = new Cat('艾米', '棕色', '小型');
Amy.echoFamily();
Amy.detail();
```
[MDN 繼承與原型鏈](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Inheritance_and_the_prototype_chain)