原型和原型鏈是 JS 中不可避免須要碰到的知識點📕,本文使用圖片思惟導圖的形式縷一縷原型、原型鏈、實例、構造函數等等概念之間的關係🌚函數
首先咱們先寫一個構造函數
Person,構造函數通常爲了區別普通函數要求首字母大寫:spa
function Person(){}
原型指的就是一個對象,實例「繼承」那個對象的屬性。在原型上定義的屬性,經過「繼承」,實例也擁有了這個屬性。「繼承」這個行爲是在 new 操做符內部實現的。prototype
先不說實例,原型與構造函數的關係就是,構造函數內部有一個名爲 prototype 的屬性,經過這個屬性就能訪問到原型:3d
Person 就是構造函數,Person.prototype 就是原型code
有個構造函數,咱們就能夠在原型上建立能夠「繼承」的屬性,並經過 new 操做符建立實例對象
比方說 Person,咱們要建立一個 person 實例,那麼使用 new 操做符就能夠實現,並經過 instanceof 來檢查他們之間的關係:blog
咱們在原型上定義一個屬性,那麼實例上也就能夠「繼承」這個屬性:繼承
實例經過 __proto__
訪問到原型,因此若是是實例,那麼就能夠經過這個屬性直接訪問到原型:圖片
因此這二者是等價的:原型鏈
既然構造函數經過 prototype 來訪問到原型,那麼原型也應該可以經過某種途徑訪問到構造函數,這就是 constructor:
所以二者的關係應該是這樣:
注意這裏的 constructor 是原型的一個屬性,Constructor 指的纔是真正的構造函數。二者名字不要弄混了😀
這裏咱們能夠看到若是實例想要訪問構造函數,那麼應當是:
沒有從實例直接訪問到構造函數的屬性或方法:
實例與原型則是經過上文中提到的 __proto__
去訪問到。
在讀取一個實例的屬性的過程當中,若是屬性在該實例中沒有找到,那麼就會循着 __proto__
指定的原型上去尋找,若是還找不到,則嘗試尋找原型的原型🐚:
咱們把註釋刪掉,給實例同名屬性,能夠看到打印出來的屬性就指向這個:
原型一樣也能夠經過 __proto__
訪問到原型的原型,比方說這裏有個構造函數 Person 而後「繼承」前者的有一個構造函數 People,而後 new People 獲得實例 p
當訪問 p 中的一個非自有屬性的時候,就會經過 __proto__
做爲橋樑鏈接起來的一系列原型、原型的原型、原型的原型的原型直到 Object 構造函數爲止。
這個搜索的過程造成的鏈狀關係就是原型鏈
以下圖:
看到 null 了麼,原型鏈搜索搜到 null 爲止,搜不到那訪問的這個屬性就是不存在的:
以上,這就是原型、原型鏈、構造函數、實例、null 之間的關係。