1.原型模式javascript
首先咱們來談談prototype屬性,也就是原型屬性。每當咱們建立一個函數時,函數內部都會自動生成一個指針(既自動生成一個屬性就是咱們說的prototype),這個指針指向指向原型對象,這個對象的用途是包含能夠由它特定類型的全部實例共享的屬性和方法,用大白話解釋這句話:就是經過用構造函數而建立的它自己這一類的那些對象實例共享原型對象中的屬性和方法。注意prototype這個屬性在函數中直接看是看不到的,咱們能夠經過打印函數的prototype來查看。原型對象中會自動生成一個constructor(構造函數)的一個屬性:這個屬性的指針會指向本函數。有人可能不知道原型對象是什麼,其實很好理解,函數的prototype屬的值其實就是一個對象(即原型對象)。
java
下面是原型與實例還有構造函數之間的關係(畫的不太好諒解。。)函數
function Hanshu(){ console.log("hi") } console.log(Hanshu.prototype)
console.log(Hanshu.prototype.constructor)
第一個console打印出來的就是原型對象(既prototype對應的值),點進去裏面會有函數的一些屬性,對象裏面有一個constructor的一個屬性。當咱們再去打印prototype屬性裏面的constructor屬性的時候打印出本函數體。this
接着咱們來看共享原型對象屬性的例子。spa
function Hanshu(a,b,c){ this.name=a; this.age=b this.job=c } Hanshu.prototype.gongxiang="我是原型對象中的一個屬性我被因此實例所共享" var a=new Hanshu("大牛","30","裝") var b=new Hanshu("大牛2","300","傻") console.log(a.gongxiang) //我是原型對象中的一個屬性我被因此實例所共享 console.log(b.gongxiang) //我是原型對象中的一個屬性我被因此實例所共享
咱們能夠看到當給Hanshu的原型對象添加屬性的時候,在Hanshu的全部實例中均可以訪問到gongxiang這個屬性,上面這段代碼解釋了函數原型對象中的屬性和方法被它的全部實例所共享。prototype
接下來咱們探索一下解釋器在讀代碼的時候,是先訪問的實例仍是原型對象的問題。指針
function Hanshu(a,b,c){ this.name=a; this.age=b this.job=c this.gongxiang="我是實例裏面的屬性" //新添加了一個屬性 } Hanshu.prototype.gongxiang="我是原型對象中的一個屬性我被因此實例所共享" var a=new Hanshu("大牛","30","裝") var b=new Hanshu("大牛2","300","傻") console.log(a.gongxiang) //我是實例裏面的屬性 console.log(b.gongxiang) //我是實例裏面的屬性
上面這段代碼惟一改變的就是咱們在函數裏面添加了一個與原型對象中屬性一致的名字,這個時候咱們再去訪問實例裏面的gongxiang這個屬性的時候發現它打印出來的是實例裏面的屬性。也就是說解釋器在讀取代碼的時候,首先先去實例裏面找gongxiang這個屬性,而後纔回去找原型裏面的屬性,注意這裏函數實例裏面的屬性屏蔽掉了原型裏面的屬性。也許這個例子讓你感受不到訪問前後順序,那咱們在來改變一下代碼位置。code
function Hanshu(a,b,c){ this.name=a; this.age=b this.job=c } var a=new Hanshu("大牛","30","裝") var b=new Hanshu("大牛2","300","傻") Hanshu.prototype.gongxiang="我是原型對象中的一個屬性我被因此實例所共享" //先建立實例在給原型添加屬性 console.log(a.gongxiang) //我是原型對象中的一個屬性我被因此實例所共享 console.log(b.gongxiang) //我是原型對象中的一個屬性我被因此實例所共享
上面這段代碼咱們又改變的代碼順序,咱們先建立裏實例,而後纔給原型添加的屬性,這個時候依然能夠訪問到gongxiang這個屬性,這就是原型模式的動態屬性,當解釋器去讀取代碼的時候,先去訪問實例中的代碼,發現沒有,而後就去訪問原型對象,發現有這個屬性,再把它讀出來。對象
關於原型對象的從寫:blog
咱們一遍一遍的重複的寫相似obj.prototype.xxx=???這樣的語法太麻煩了,既然原型對象是對象,那咱們能夠直接去定義原型對象,能夠同樣問題來了constructor原本是原型對象裏面自動執行函數自己的,因爲從寫constructor再也不執行原函數。還有書上並無說從寫原型對象之後,原型對象是否還跟屬性共享的問題。請看如下代碼
function Abc(){ } Abc.prototype={ name:"ffk", age:10, job:"work" } var Hanshu=new Abc() console.log(Hanshu.name)//ffk
console.log(Abc.prototype)//
原型從寫之後原型對象裏面的屬性和方法依舊被共享。但是當咱們去打印構造函數的原型對象的時候,constuctor再也不指向函數自己,而是繼承obj。
其實從寫原型函數帶來的問題仍是有一些的,咱們繼續看一下代碼
function Abc(){ } var Hanshu=new Abc() //換了位置放到了前面 Abc.prototype={ name:"ffk", age:10, job:"work" } console.log(Hanshu.name)// undefined
★★★重要
當咱們把對象建立放到從寫原型對象以前,發現再去訪問的時候,已經找不到屬性了,雖然以前咱們說過解釋器在讀代碼的時候先去實例裏面找而後再去原型裏面找(動態屬性)。
在從寫原型對象的狀況下,也就是說咱們建立對象實例以前,你並無告訴解釋器個人原型對象要換對象了,因此在它建立實例的時候它的實例內部指針還指向的是默認的那個最初的原型對象,等你後面再從寫原型對象的時候已經晚了,最初原型對象中只有coustructor屬性,沒有name,因此打印出來是undefined(書上不是這樣說的,我是按我本身的理解來解釋的,我感受這樣說比書上更好理解。。你們這樣理解就好了沒問題的)。