DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> JavaScript入門知識 >> 關於JavaScript >> Javascript之旅 對象的原型鏈之由來
Javascript之旅 對象的原型鏈之由來
編輯:關於JavaScript     
以問題開始:

function Base(){}var base = new Base()
上面兩行代碼會創建幾個對象(object)?

要回答這個問題,先明確一下Javascript裡object的概念。


Objects

在Javascript裡,幾乎一切都是object(Arrays、Functions、Numbers、Objects……),而沒有C#裡的class的概念。object的本質是一個name-value pairs的集合,其中name是string類型的,可以把它叫做“property”,value包括各種objects(string,number,boolean,array,function…),指的是property的值。


typeof

既然object包含Arrays、Functions、Numbers、Objects……,那怎麼區分這些呢?答案是typeof。 typeof返回一個字符串,如typeof(Null) = “object”,typeof(false) = “Boolean”, typeof(1) = “number”。既然總是返回字符串,那麼對於typeof (typeof x),不管x是什麼,總是返回”string”。


Constructor

JS裡沒有class,也就沒有class裡的構造函數,那麼object是怎麼被創建的呢?用構造器:constructor。constructor其實就是Function,因此本身也是object。開頭的function Base(){}就是一個構造器,var b = new Base()就是用這個構造器(通過關鍵字new)創建了一個叫b的object。至此我們可以得出結論,開頭的兩行代碼至少創建了2個object:一個是Base,類型為function的object,一個是base,類型為object的object。

 

Function()和Object()

這是兩個重要的預定義好的構造器。一切function(比如開頭的Base())都是由Function()構造出來的;而Object的prototype將會被所有object繼承,下面會講到。

    

 

Function的創建過程

當執行function Base(){this.a = 1}時,相當於var Base = new Function(“this.a = 1”),也就是說,這行代碼本身,將使用預定義好的Function() constructor,來構造一個function型object(即Base)出來。在這個創建過程中,js將做哪些事呢?

  1, 首先當然會創建一個object起來,Base指向這個object。typeof 這個object = “function”
     
  2, 給Base附上__proto__屬性,讓它等於Function這個構造器的prototype(也是預定義好的)。這是很重要的一步,也是規律性的一步。(規律:)在執行任意類似varx = new X()時,都會把X的prototype賦給x的__proto__,也就是說,x.__proto__和X.prototype此時會指向同一個對象。

     
  3, 為Base創建call屬性,該屬性是個function。因此我們可以這樣寫:Base.Call()

     
  4, 為Base創建Construct屬性,該屬性也是個function。在執行var base = new Base()時,即會調用這個Construct屬性。
  5, 為Base創建Scope,Length等屬性,略。
  6, 為Base創建prototype屬性:先用new Object()創建一個對象,為這個對象創建一個屬性叫constructor,該屬性值設置為Base。再把Base的prototype設置為這個新創建的對象。偽代碼如下:

var x = new Object();
x.constructor = Base;
Base.prototype = x;

 

先把關注點放到2和6。

 

__proto__和prototype

從2可以看出來,任意一個用構造器構造出來的object(包括Objects和Functions),都會有__proto__屬性,指向該構造器的prototype屬性。注意__proto__是個私有屬性,在IE上是看不到的,我用的是chrome,可以看到。

從6可以看出,任意一個用new Function()構造出來的functions,都會有prototype屬性,該屬性是用new Object()構建出來的,初始公開屬性只有一個constructor。

    

 

原型鏈

再來分析下第6步的偽代碼,也就是為function創建prototype的這一步:

var x = new Object(); // 參見2中的規律,會有x.__proto__= Object.prototype。
x.constructor = Base;
Base.prototype = x;

此時我們用Base()構造一個對象出來:

var base= new Base(); // 參見2中的規律,會有base.__proto__ = Base.prototype,也就是 = x。  // 因此有base.__proto__.__proto__ = x.__proto__ // 而x.__proto__ = Object.prototype(見上一個代碼片段)   // 所以,base.__proto__.__proto__ = Object.prototype.

__proto__.__proto__,這就是傳說中JS對象的原型鏈!由於用Function()創建構造器時的關鍵的第6步,保證了所有object的原型鏈的頂端,最終都指向了Object.prototype。

    

 

Property Lookup

而我們如果要讀某個object的某個屬性,JS會怎麼做呢?

比如有個object叫xxx,我們執行alert(xxx.a),也就是讀取xxx的a屬性,那麼JS首先會到xxx本身去找a屬性,如果沒找到,則到xxx.__proto__裡去找a屬性,由此沿著原型鏈往上,找到即返回(沒找到,則返回undefined)。可以來看個例子:

    

上圖得知:base本身是沒有constructor屬性的,但是base.constructor確實能返回Base這個函數,原因就在於base.__proto__有這個屬性。(base.__proto__是啥?就是Base.prototype,上面構建Function的第6步的偽代碼裡,為Base.prototype.constructor賦值為Base本身。)

 

Object作為“基類”

另外,由於任意object的原型鏈的頂端都是Object.prototype。所以,Object.prototype裡定義的屬性,就會通過原型鏈,被所有的object繼承下來。這樣,預定義好的Object,就成了所有對象的“基類”。這就是原型鏈的繼承。

    

看上圖,Object.prototype已經預定義好了一些屬性,我們再追加一條屬性叫propertyA,那麼這個屬性和預定義屬性一樣,都可以從base上讀到。

 

原型繼承

已經得知,

對於 var xxx =new Object(); 有xxx.__proto__= Object.prototype;

對於 var xxx =new Base(); 有xxx.__proto__.__proto__= Object.prototype;

看上去很像什麼呢?從c#角度看,很像Base是Object的子類,也就是說,由Base()構造出來的object,比由Object()構造出來的object,在原型鏈上更低一個層級。這是通過把Base.prototype指向由Object()創建的對象來做到的。那麼自然而然,如果我想定義一個繼承自Base的構造器,只需把改構造器的prototype指向一個Base()構造出來的對象。

function Derived(){}
var base = new Base();
Derived.prototype = base;
var d = newDerived(); //很容易推算出:d.__proto__.__proto__.__proto__ = Object.prototype.

推算過程:d.__proto__指向Derived.prototype,也就是base;則__proto__.__proto__指向base.__proto__,也就是Base.prototype,也就是某個new object()創建出來的東東,假設是o;則__proto__.__proto__.__proto__指向o.__proto__,也就是Object.prototype。

 

回答開頭的問題,以及幾個新的問題

那兩行代碼至少創建了三個對象:Base、base、Base.prototype。順便說說,base是沒有prototype屬性的,只有function類型的object,在被構建時才會被創建prototype屬性。

    

 

d.constructor會返回什麼呢?

構造器Base()和Derived()裡都是空的,如果有代碼,將會怎麼被執行呢?

……

待續。見下篇

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved