--- 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)