1. 程式人生 > >javascript原型繼承分析(prototype)

javascript原型繼承分析(prototype)

一直恪守的原則就是,要用一個東西,那麼一定要對這個東西非常的瞭解才可以,這樣在用的時候才能做到心裡有底、、或者說心裡有數。。。。接觸node.js也算是有一段的時間了,也拿它做了一些的東西,以前的一片文章算是分析了javascript的閉包原理,但是自己一直沒有將javascript的原型機制搞清楚,趁著現在比較的閒,靜下來將這一塊先搞定。。。。

首先我們來看一句比較奇怪的程式碼:

[javascript] view plaincopy
  1. console.log(typeof Object);  

這裡的輸出會比較的神奇:function

也就是說Object本身是一個function,那麼我們用如下的程式碼來看看這個Object這個function是怎麼定義的吧:

[javascript] view plaincopy
  1. console.log(Object.toString());  

那麼這段程式碼的輸出是: function Object() { [native code] }

好吧,到這裡我們可以下結論Object是一個函式,而且這個函式的實現是javascript引擎內部的,對於這部分就無能為力了。。。

根據《javascript高階程式設計》以及《javascript語言精粹》的說法,可以畫出如下的圖形:


這裡因為Object是一個function,所以它有一個prototype屬性和一個name屬性,name的屬性的值就是“Object”,而prototype則指向了它的原型物件,而其原型物件中又包含一個constructor屬性指向當前的Object函式。。。

好了,接下來我們來看看按照物件字面量建立物件吧,程式碼:

[javascript] view plaincopy
  1. var aa = {};  
  2. aa.name = 'fjs';  

上面通過字面量的方式建立了一個物件,並用aa來引用它,而且給了它一個name的屬性,這個時候可以用如下的圖來表示aa:


上圖的意思就是說剛剛建立的aa物件中有一個名字叫做__proto__的屬性指向了Object的prototype,而且這個屬性是預設新增上去的,這是一個內部的屬性,預設按照ECMA的規定,它是不可以訪問的,但是很多javascript引擎都通過__proto__這個名字來引用這個屬性。。

我們可以用如下的程式碼來驗證:

[javascript] view plaincopy
  1. var aa = {};  
  2. aa.name = 'fjs';  
  3. console.log(aa.__proto__ === Object.prototype);  

輸出的結果是true,那麼上面的圖形也就得到了驗證。。。

接下來我們來看看另外一種構造物件的方法,建構函式,先來看一個建構函式的定義:

[javascript] view plaincopy
  1. function Fjs() {  
  2.     this.name = "fjs";  
  3. }  

這裡我們用另外一張圖來表示當前的情形:


這張圖形可以用如下的程式碼進行驗證:

[javascript] view plaincopy
  1. function Fjs() {  
  2.     this.name = "fjs";  
  3. }  
  4. console.log(Fjs.prototype.constructor === Fjs);  
  5. console.log(Fjs.prototype.__proto__ === Object.prototype);  

上述的兩個輸出都是true,那麼上面的圖形也就得到了驗證,接下來我們來看看呼叫建構函式來建立物件都做了什麼事情,也就是如下程式碼:

[javascript] view plaincopy
  1. function Fjs() {  
  2.     this.name = "fjs";  
  3. }  
  4. console.log(Fjs.prototype.constructor === Fjs);  
  5. console.log(Fjs.prototype.__proto__ === Object.prototype);  
  6. var fjs = new Fjs();  

這種方式構造物件,其實javascript引擎是這麼搞的:

(1)建立一個新的物件

(2)將當前建構函式的作用域指向剛剛建立的新物件,也就是將建構函式的this指向剛剛建立的物件,而且要為這個物件的內部__proto__屬性賦值,用它指向當前建構函式的prototype屬性

(3)執行建構函式中的程式碼,也就是呼叫this,為剛剛建立的物件賦值

(4)返回該物件

那麼根據上述的步驟,我們又可以得到如下的圖形:


對於上述的圖形,我們可以用如下的程式碼來進行驗證:

[javascript] view plaincopy
  1. function Fjs() {  
  2.     this.name = "fjs";  
  3. }  
  4. var fjs = new Fjs();  
  5. console.log(fjs.__proto__ == Fjs.prototype);  

輸出是true,那麼上述的圖形也就得到了驗證,其實從這裡也就能夠看到javascript所謂的原型鏈了。。。

到這裡為止應該算是對javascript的原型模式有了一定的瞭解了吧。。不至於像以前一樣裸奔了。。。