在開始講原型和原型鏈以前,咱們先確認如下幾個概念:git
先知道以上3點,下面咱們一步一步來講明:github
第一步:咱們建立一個構造函數Personsegmentfault
function Person(name){
this.name = name; // 屬性name
this.sayHello = function(){ // 方法sayHello
console.log(name + 'say hello');
}
}複製代碼
如今建立一個實例對象moose並傳入名字「moose」數組
var moose = new Person('moose');複製代碼
這時候咱們來打印一下,看看moose是否是擁有Person的屬性和方法瀏覽器
moose.sayHello(); // moose say hello複製代碼
咱們知道moose這個對象在建立的時候並無直接建立sayHello()方法,即便你們知道從Person中繼承過來的,那究竟是怎麼實現的呢?這就是咱們接下來要講的原型和原型鏈。bash
在Person這個構造函數定義的時候,同時建立的還有一個與之關聯的「原型對象」,這個對象畢竟不是咱們手動建立命名的一個對象,那要使用這個「原型對象」怎麼辦呢?JS提供了一個屬性「prototype」給函數。Person.prototype就指向這個「原型對象」。函數
這個時候咱們經過Person這個構造函數建立了一個實例對象「moose」,要想實現繼承這樣一個關係,moose必須可以使用Person中的屬性和方法。JS的作法是給實例對象提供了一個"__proto__"的屬性,moose.__proto__也指向Person對應的這個實例對象。這樣咱們就得出了一個小結論:this
console.log(Person.prototype === moose.__proto__); // true複製代碼
到目前爲止,原型鏈繼承就實現了。spa
第一步原型關係圖以下:prototype
第二步:既然實例對象和構造函數均可以指向原型,那麼原型是否有屬性指向構造函數或者實例呢?
很遺憾,原型沒有指向實例對象的屬性,可是指向構造函數的有啊~:constructor登場
console.log(Person === Person.prototype.constructor); // true複製代碼
既然說了原型相關的概念,咱們不妨在說一下原型鏈,簡單的說,原型鏈就是一條由一堆上下等級分明的原型組成的繼承鏈。
第三步:就上面的例子而言:moose經過__proto__找到本身的原型,繼承原型對應函數的屬性和方法。那麼咱們難想到,原型對象自己就是一個對象呀,也擁有__proto__屬性,那麼它的原型又會是什麼呢?
console.log(Person.prototype);複製代碼
console.log(Person.prototype.__proto__ === Object.prototype); // true複製代碼
從瀏覽器中打印出的結果頁能夠看到,Object.prototype原型的constructor屬性指向的是Object函數。
那麼Object.prototype的原型又是什麼呢?
console.log(Object.prototype.__proto__); // null複製代碼
這就說明Object.prototype 已經沒有原型了,Object對象是根對象。
以上一整個查找原型的過程走的就是這樣一條清晰的原型鏈。
拓展問題:instanceof原理是什麼?
// 咱們以數組爲例
var arr = []
arr instanceof Array複製代碼
instanceof原理就是利用了原型鏈,當執行arr instanceof Array時,會從arr的_proto_一層一層往上找,看是否能不能找到Array的prototype。
咱們知道var arr = [] 實際上是var arr = new Array()的語法糖,因此arr的_proto_指向Array的prototype,結果返回true
到此爲止,咱們大致的梳理了一下原型以及原型鏈相關的內容
特別感謝提供相關內容參考:
附:感謝您的閱讀,但願對您有所幫助。若是以上內容中存在疑問和錯誤,歡迎留言或者私信。