Js中的原型鏈的解釋

A)      關於prototype chain有幾點說明:

  a.      這個鏈的終點是Objectprototype對象:Object.prototype

  b.      所有的對象在默認的情況下都有一個原型(__proto__.

  c.      原型本身也是對象,所以每個原型自身又有一個原型(__proto__),除了Object.ptototype.

關於c這個觀點可以用一下面的小程序來證明:

[javascript] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. function A(){}  
  2. console.log(A.prototype.__proto__);//Object {}  
  3. console.log(Object.prototype.__proto__);//null  

 就這上面兩個輸出,下面做詳細的分析,並說明這個proto鏈是怎麼形成的。

1)  先定義一個簡單的函數並創建該函數的對象 var a = new A(); 注意,這裏a,沒有自己的屬性,它的所有的屬性都從原型對象上繼承而來)現在看看內存中這個對象的具體情況

 

                                                                                          圖 1.1 

觀察圖1.1,可以發現a對象的__proto__屬性,這個論證了觀點b的正確性。觀察prototype對象有一個__proto__屬性(綠色方框所示)。這個就說明了觀點b的正確性。

但是,prototype的__proto__所代表的對象是誰呢?查看@37891發現,這個對象是一個Object對象,其實說白了就是Object.prototype所指向的對象。下面給出該對象的內存情況:

                                                圖 1.2

觀察這個對象的constructor,其指向Object的構造器。對比圖1.1可以發現,這個對象是沒有__proto__屬性的,這個對象正是a對象所在的proto鏈條的終點:Object.pototype.

結合上面的說明,可以得到如下圖示:


                                       圖 1.3


注意:沿着紅色箭頭組成了proto鏈!!!所以console.log(A.prototype__proto__)爲Object{},而Object.prototype.__proto__爲null.

B)      通過這個prototype chain可以實現屬性的繼承,例程如下:

[javascript] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. function A(x){  
  2.     this.x = x ;  
  3.   }  
  4.   
  5.   function B(y) {  
  6.     this.y = y;  
  7.   }  
  8.   
  9.   B.prototype = new A(1);  
  10.   
  11.   function C(z) {  
  12.     this.z = z;  
  13.   }  
  14.   
  15.   C.prototype = new B(2);  
  16.   
  17.   var c = new C(3);  
  18.   var sum = c.x+c.y + c.z;//sum == 6  
可以通過chrome瀏覽器的Take Heap Snapshot來查看對象c的prototype chain。如下圖
 

                    圖 1.4

 先逐步分一下各個對象的內存分析圖:查看一下@14285對象(A的對象)的prototype chain:(留意一下@後面的數字)。

 
                       圖 1.5


用圖形表現其prototype chain如下:

                                                圖1.6

通過上圖分析,有如下關係:


[javascript] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. a.__proto__ === A.prototype,  
  2.   
  3. A.prototype.__proto__===Object.prototype  

再看看@14295所代表的對象(B的對象)的prototype chain:

                                        圖1.7


用圖形表現其prototype chain如下:

                                  圖1.8

[javascript] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. b.__proto__ === B.prototype  
  2.   
  3.   B.prototype.__proto__ === A.prototype  
  4.   
  5.  A.prototype.__proto__ === Object.prototype   

說明:圖1.8的B.prototype所代表的對象,其實是圖1.6中的對象a,因爲B.prototype的@後面的數字和a對象@後面的數字是一樣的。所以在這裏特地把它們的顏色標識爲綠色,以示爲同一個對象。其餘顏色相同的@+數字,代表着同樣的意思。

所以圖1.8和圖1.7合併起來可以另外表示爲:


                                                                 圖 1.9

到這裏,B的prototype chain已經和A的prototype chain連接起來了。鏈接起來的關鍵代碼就是B.prototype = new A(1);

同理,再看看對象c的prototype chain:

                     圖 2.0

用圖形表示爲:

                   

                        圖  2.2

  C.__proto__=== C.prototype

 C.prototype. __proto__ == a

  注意藍色@14295,可以得出c. __proto__== b,在代碼中體現爲C.prototype = new B(2);

所以圖2.1還可以表示爲:


  同時也可以發現,javascript對象屬性搜索的過程是由近到遠的順序,如果c對象中有了y屬性,那麼C.prototype的屬性y是不會訪問到的。

Var c = new (3);

c.y = 4;//

var sum = c.x +c.y ;//==5而不是==3

注意代碼c.y = 4;這是個賦值操作,而不是取值操作;對於賦值操作,javascript總是在原始對象(在這裏是c對象)創建屬性或者對已有的屬性賦值,而不會去修改原型鏈。在javascript中只有查詢屬性(取值操作)時纔會體現到繼承的存在,而設置屬性則和繼承無關。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章