JavaScript原型及原型鏈

在上一講當中我們知道了new 一個函數時this的指向,接下來我們就分析一下這裡的原型類和原型鏈。

原型類

定義:原型類是function函數下的一個屬性,它定義類構造函數構造出的對象的公共祖先。通過該構造函數產生的對象,可以繼承該原型的屬性和方法。

JavaScript原型及原型鏈


person1與person2同時擁有name和age屬性,我們如下圖分析:

JavaScript原型及原型鏈

Person構造函數的prototype屬性指向了Person.prototype原型類對象,所以可以說Person.prototype原型類是構造函數Person的一個屬性

需要重點說明一下:一個原型對象,其中的方法、屬性,平時它的構造器是無法訪問到原型裡面的方法、屬性的,但當執行new後,它構造出的實例對象便可以訪問原型裡面的方法、屬性。雖然可以訪問裡面的屬性、方法,但不能直接修改原型類裡面的值,故:person1.name=‘sunxiaoqiang’ => 這不是在修改原型類中的name屬性,而是在給person1增加一個name屬性;如果一定要修改原型類裡面的值(感覺沒有必要)通過上圖我們可以這樣:person1.constructor.prototype.name=’sunxiaoqiang’

JavaScript原型及原型鏈


依次輸出:

sunqiang

Sundaqiang

介紹到這裡,我們應該明白,可以利用原型類提取一些公共屬性,以便於每個實例都擁有這些屬性。

為了深刻了解原型類,我們分析一個例子:

JavaScript原型及原型鏈


此時person的name屬性還是sunqiang,分析:

當new一個Person函數返回this時,this裡面有一個屬性_proto_內部屬性,其值指向Person.prototype

我們可以這樣理解:按執行順序走,當new Person函數時,this中的_proto_指向Person.Prototype,而這個Person.Prototype指向一個對象,此對象裡有一個name屬性。當我們重新給Person.Prototype重新賦值時,會不會影響this的_proto_指向,答案是不會的,我們如下圖分析:

JavaScript原型及原型鏈

我們不難發現,this屬性_proto_的指向不變。

原型類我們有了一些概念了,接下來看看由原型構建出來的原型鏈。

原型鏈

JavaScript原型及原型鏈


畫圖分析一下:

JavaScript原型及原型鏈

將SubClass的prototype指向SuperClass的實例對象,new SuperClass函數發生的什麼上面已經介紹,通過圖我們發生SubClass、SuperClass、SuperClass prototype和Object它們之間形成了一個鏈子,這就構成了原型鏈。在這裡也形成了簡單的原型鏈繼承,我們發現它們最終都繼承自Object.prototype=>Object。

當查詢一個屬性或方法時,首先在子類自身找,如果沒有在向父類找,一層一層查詢;刪除也是一樣,子類有的屬性或方法就會刪除,不影響父類級別的。

可以這麼說任何對象都會有toString()方法,不管對象自身有沒有這個方法,它們都繼承自Object.prototype方法。

當我們寫一個空對象({}),然後調用toString()方法,返回的是一個”[object Object]”,那為什麼我們給num變量賦值一個數字123,然後調用num.toString()方法返回是一個字符串”123”呢?

原因就是num是Number類型,它屬於包裝類,此類重寫類toString()方法,因為繼承所以在訪問這個方法時優先找自身的。

像Array.prototype、Array.prototype、Boolean.prototype、String.prototype都重寫的父類的toString()方法。

基於上面的知識點,我們可以為自己使用的對象進行擴展。

JavaScript原型及原型鏈

當我們需要知道數據類型時,比如:Number、Boolean、Array、String這些類型時,那我們還是需要調用Object.prototype方法,因為這個方法會依次顯示”[object Number]”,”[object Boolean]”,”[object Array]”,”[object String]”進而區分數據類型,應該如何調用呢,後續我再講call時會提到,敬請關注


分享到:


相關文章: