
圖解原型和原型鏈
原型和原型鏈是 JS 中不可避免需要碰到的知識點?,本文使用圖片思維導圖的形式縷一縷原型、原型鏈、例項、建構函式等等概念之間的關係?
Constructor 建構函式
首先我們先寫一個建構函式
Person,建構函式一般為了區別普通函式要求首字母大寫:
function Person(){}
複製程式碼
prototype 原型
原型指的就是一個物件,例項“繼承”那個物件的屬性。在原型上定義的屬性,通過“繼承”,例項也擁有了這個屬性。“繼承”這個行為是在 new 操作符內部實現的。
先不說例項,原型與建構函式的關係就是,建構函式內部有一個名為 prototype 的屬性,通過這個屬性就能訪問到原型:

Person 就是建構函式,Person.prototype 就是原型

instance 例項
有個建構函式,我們就可以在原型上建立可以“繼承”的屬性,並通過 new 操作符建立例項

比方說 Person,我們要建立一個 person 例項,那麼使用 new 操作符就可以實現,並通過 instanceof 來檢查他們之間的關係:

我們在原型上定義一個屬性,那麼例項上也就可以“繼承”這個屬性:

proto 隱式原型
例項通過 __proto__
訪問到原型,所以如果是例項,那麼就可以通過這個屬性直接訪問到原型:

所以這兩者是等價的:

constructor 建構函式
既然建構函式通過 prototype 來訪問到原型,那麼原型也應該能夠通過某種途徑訪問到建構函式,這就是 constructor:

因此兩者的關係應該是這樣:

注意這裡的 constructor 是原型的一個屬性,Constructor 指的才是真正的建構函式。兩者名字不要弄混了?
例項、建構函式、原型之間的關係
這裡我們可以看到如果例項想要訪問建構函式,那麼應當是:

沒有從例項直接訪問到建構函式的屬性或方法:

例項與原型則是通過上文中提到的 __proto__
去訪問到。
在讀取一個例項的屬性的過程中,如果屬性在該例項中沒有找到,那麼就會循著 __proto__
指定的原型上去尋找,如果還找不到,則嘗試尋找原型的原型?:

我們把註釋刪掉,給例項同名屬性,可以看到列印出來的屬性就指向這個:

原型鏈
原型同樣也可以通過 __proto__
訪問到原型的原型,比方說這裡有個建構函式 Person 然後“繼承”前者的有一個建構函式 People,然後 new People 得到例項 p
當訪問 p 中的一個非自有屬性的時候,就會通過 __proto__
作為橋樑連線起來的一系列原型、原型的原型、原型的原型的原型直到 Object 建構函式為止。
這個搜尋的過程形成的鏈狀關係就是原型鏈

如下圖:

看到 null 了麼,原型鏈搜尋搜到 null 為止,搜不到那訪問的這個屬性就是不存在的:

以上,這就是原型、原型鏈、建構函式、例項、null 之間的關係。
