iT邦幫忙

0

Javascript 進階 6-6 原型鏈、建構函式整體結構概念

這個章節要來複習第六章所學到的觀念

https://ithelp.ithome.com.tw/upload/images/20200404/20121770KRho7pohVL.png

  1. 首先,比比這隻狗是一個實體(instance),是繼承了 狗的原型。
  2. 狗的原型 又繼承了 動物的原型。
  3. 動物的原型 又繼承了 物件的原型。

那麼動物的原型因為是比較高的階層,所以我們又可以有別的動物來繼承動物的原型,在上一張的最後則是由貓的原型來繼承

  1. 貓的原型 繼承了 動物的原型,也有自己的方法。
  2. 並且也可以透過貓的原型產生貓的實體。貓的實體 也是繼承了 貓的原型。

好~說到這裡感覺很像繞口令齁~ 我們用下面這張表來看一下這些東西的互相關係

https://ithelp.ithome.com.tw/upload/images/20200404/201217707YsOUn3E2k.png

那麼為了讓畫面簡潔一點呢,這邊沒有顯示出貓的實體以及貓的原型!

另外呢畫面上有綠色字體顯示的,Dog、Animal、Object、Function,這些呢都是屬於建構函式

首先呢我們先專注在最左上方的比比(狗的實體),如果我們使用console.log來看比比的話,就會顯示出這樣的結果。

那麼比比的內容呢,有包含了 name、family、color以及這個章節介紹的重點 __proto__

這個 __proto__ 會指向狗的原型,而狗的原型就是透過狗的建構函式而來,所以狗的原型的 constructor 會指向 狗的建構函式。

https://ithelp.ithome.com.tw/upload/images/20200404/20121770KG0Ju8utak.png

同時狗的原型的 __proto__ 也可以向上尋找,找到動物的原型。

每一個原型都會有一個 constructor 去指向這個建構函式。

所以動物的原型的 constructor 就會去指向動物的建構函式

然後動物的 __proto__ 也可以向上尋找,找到物件的原型。

然後物件的原型的 constructor 也會連結到 物件的建構函式。

如果物件的建構函式的 __proto__ 繼續向上尋找,最後會找到 null 的結果。

https://ithelp.ithome.com.tw/upload/images/20200404/20121770Rv9kWU6dfd.png

了解到這裡,其實你已經掌握了絕大部分的概念,那麼我們再多說一些觀念吧!

首先先把剛剛的部分調淡一些些。

https://ithelp.ithome.com.tw/upload/images/20200404/20121770WvNMeQCmAq.png

剛剛的 Dog、Animal、Object 都可以利用 Dog、Animal、Object.prototype 來產生原型或是將方法掛載在這些建構函式的原型鏈上。

那麼為什麼,我們可以使用 prototype 這個方法呢?

那是因為 Dog、Animal、Object 的 __proto__ 都是繼承於 Function 這個建構函式的 prototype。

https://ithelp.ithome.com.tw/upload/images/20200404/2012177017JIF6SAzv.png

最後我們再來看一下 函式, Function 的原型。

Function 的原型的 __proto__ 繼續向上尋找,一樣會找到物件的原型。

Function 的原型的 constructor 會指向 Function 的建構函式。

Function 的建構函式的 __proto__ 則會指向回 Function 的原型。

https://ithelp.ithome.com.tw/upload/images/20200404/20121770kjyh1VvM6C.png

接著就來用程式碼來驗證一下吧!

function Animal (family) {
    this.kingdom = '動物界';
    this.family = family || '人科';
}

Animal.prototype.move = function () {
    console.log(this.name + ' 移動');
};

function Dog (name, color, size) {
    Animal.call(this, '犬科');
    this.name = name;
    this.color = color || '白色';
    this.size = size || '小';
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function () {
    console.log(this.name + '吠叫');
}

var Bibi = new Dog('比比', '棕色', '小');

console.log(Bibi.__proto__ === Dog.prototype);

透過這樣的結果我們可以知道 這個 proto 會指向狗的原型,而狗的原型就是透過狗的建構函式而來,這個觀念是對的。

那我們繼續再加上~

console.log(Bibi.__proto__.__proto__ === Animal.prototype);

https://ithelp.ithome.com.tw/upload/images/20200404/20121770TmmxVeAD6l.png

所以往上找兩層也就是 狗實體 >> 狗原型 >> 動物原型,而答案也是 true。

再來驗證建構器 constructor 的觀念

那我們繼續再加上~

console.log(Bibi.__proto__.__proto__.constructor === Animal);

https://ithelp.ithome.com.tw/upload/images/20200404/20121770iwPmiv0mrH.png

那麼 動物原型 的 建構器 很明顯就應該要是動物的建構函式,答案一樣也是 true,代表的確動物的原型的 constructor 是指向動物的建構函式。

再來驗證原型鏈的最上層會是 null

那我們繼續再加上~

console.log(Bibi.__proto__.__proto__.__proto__.__proto__ === null);

https://ithelp.ithome.com.tw/upload/images/20200404/201217707AW7EkFaSD.png

那麼驗證的結果也是 true。

驗證 所有的建構函式都是繼承 Function 的原型

那我們繼續再加上~

console.log(Dog.__proto__ === Function.prototype);
console.log(Animal.__proto__ === Function.prototype);
console.log(Object.__proto__ === Function.prototype);

https://ithelp.ithome.com.tw/upload/images/20200404/20121770Dy3PxTksl2.png

驗證 Function 的 __proto__ 是否指向 Function 的原型

那我們繼續再加上~

console.log(Function.__proto__ === Function.prototype);

https://ithelp.ithome.com.tw/upload/images/20200404/20121770WigAQXNMJH.png

同時,Function 的原型再向上尋找就會找到物件的原型喔!

那我們繼續再加上~

console.log(Function.__proto__.__proto__ === Object.prototype);

https://ithelp.ithome.com.tw/upload/images/20200404/20121770eOuP3IYSEl.png

所以這個觀念也被驗證!

以上就是原型鏈以及繼承的關係,也可以參考 MDN 繼承與原型鏈的文章

來更深入的學習喔!

沒問題的話就可以來做做後面的習題喔!


尚未有邦友留言

立即登入留言