沒有眼淚
          Don't Cry!
          posts - 13,comments - 44,trackbacks - 0
                  眾所周知,javascript中的繼承是通過原型對象(prototype)來實現的.原型對象是由函數的構造函數創建,它所擁有的屬性能被所有對象共享.初始時原型對象指向一個Object對象,并且定義了一個constructor屬性,該屬性指向定義該原型對象的構造函數本身,上述過程可以理解為以下代碼:
          function BaseClass() {
              document.write('This is BaseClass.');
          }
          BaseClass.prototype 
          = new Object();
          BaseClass.prototype.constructor 
          = BaseClass;
          因為原型對象的所有屬性能被構造函數創建對象共享,所以創建的對象可以訪問這里的constructor屬性:
          var c = new BaseClass();
          document.write(c.constructor 
          == BaseClass); //true
          c.constructor(); //調用BaseClass函數,輸出This is BaseClass.
          由于對象本身也可以自定義屬性,所以在讀取對象屬性時js先檢查該對象是否定義了該屬性,如果已經定義了則使用該屬性,如果沒有定義則再從其原型對象中讀取該屬性,所以如果對象自定義的屬性和其原型中的屬性存在重名則自定義屬性"隱藏"了其原型對象中的同名屬性.例:
          c.constructor = function() {
              document.write('This is c');
          }
          c.constructor(); 
          //This is c
          加入上述代碼之后再次調用c.constructor(),則會打印出"This is c".這是因為c已自定義constructor屬性"隱藏"了其原型對象中的constructor屬性.當然js保證了讀寫的不對稱性,也就是說讀取一個對象的屬性時有可能要從其原型對象中去讀取,但寫一個對象的屬性時卻從不涉及其原型對象,無論在一個對象加入或修改多少屬性這都不影響其原型對象中屬性的本來面目.比如這里c自定義了constructor屬性,但這一行為并不影響其原型對象中constructor指向其構造函數這一事實,如果再創建一個對象且不自定義constructor屬性,再調用constructor則依然調用對象的構造函數,例:
          var b = new BaseClass();
          b.constructor(); 
          //調用BaseClass函數,輸出This is BaseClass.

          很容易理解js為什么這樣做,因為一個對象的行為不能影響到其他對象,否則將會造成混亂.
                  理解上述規則之后讓我們看看js中是如何通過原型對象實現繼承的.當我們創建一個對象時,可以把該對象看成是由2部分組成的,一部分存儲了該對象自己定義的屬性(稱為A部分),而另一個部分則存儲了其構造函數所定義的原型對象引用(稱為B部分),例如這里的BaseClass.prototype.當讀取對象的屬性時可以分為以下2步:
          1.js先檢查該對象引用所指向的內存區域的A部分是否存在該屬性,如果存在則讀出.
          2.如果沒有則再從B部分存儲的引用(BaseClass.prototype)所指向的內存區域中讀取該屬性.

          從步驟2開始這就是個不斷往上尋找的過程,因為BaseClass.prototype所指向的內存區域也會分為A和B兩個部分,如果再A部分也不存在該屬性,則又會從其B部分所指向的內存區域去尋找該屬性,而該內存區域也有A和B兩個部分,如果A部分仍然不存在,則還要從B部分所指向的內存區域去尋找該屬性,直到達到最頂層的Object類.所以在無形當中就形成了一條鏈,也就是我們常說的原型鏈.如果理解了這個過程我想也就能了解原型對象了.下面簡單分析下b.constructor();的調用過程便于加深理解.
          1.js會在b所指向的內存區域A部分讀取constructor屬性.
          2.當發現沒有該屬性后再從其類的構造函數原型對象引用所指向的內存區域讀取該屬性.因為原型對象引用初始時指向一Object對象內存區域(BaseClass.prototype = new Object();)
          3.再從此Object對象的A部分尋找constructor屬性.
          4.沒有找到該屬性則從其類的原型對象即Object.prototype中去尋找constructor.
          5.如果找到該屬性則調用.
          6.否則,到達鏈的頂端,返回.
          到此能很清楚的知道js中是如何實現繼承的,如果我們自定義的類不想繼承自Object,則可以修改其prototype的指向,可以讓其指向任意一個類,這樣也就實現了繼承自定義類,但js中所有的類都繼承自Object類,所以原型鏈的關系仍然存在.

          posted on 2008-05-09 16:43 zhangchao 閱讀(1056) 評論(3)  編輯  收藏 所屬分類: javascript

          FeedBack:
          # re: 我所理解的原型對象[未登錄]
          2008-12-07 19:10 | simon
          受教  回復  更多評論
            
          # re: 我所理解的原型對象
          2010-06-08 12:41 | #
          非常不錯  回復  更多評論
            
          # re: 我所理解的原型對象
          2013-03-12 15:25 | liger 博客園
          非常的好,情不自禁的轉了  回復  更多評論
            
          主站蜘蛛池模板: 台前县| 宁蒗| 西藏| 舒兰市| 崇礼县| 长宁县| 中方县| 陇西县| 青岛市| 彭山县| 马龙县| 忻州市| 醴陵市| 蒙自县| 遵义市| 伽师县| 乐都县| 彝良县| 绥阳县| 田东县| 新安县| 桑植县| 肥东县| 绥棱县| 南投市| 崇州市| 黎川县| 河间市| 天峨县| 绥棱县| 乌什县| 抚州市| 克什克腾旗| 房产| 马关县| 太原市| 平舆县| 遵义县| 陕西省| 东阿县| 四川省|