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

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

          從步驟2開始這就是個(gè)不斷往上尋找的過程,因?yàn)锽aseClass.prototype所指向的內(nèi)存區(qū)域也會(huì)分為A和B兩個(gè)部分,如果再A部分也不存在該屬性,則又會(huì)從其B部分所指向的內(nèi)存區(qū)域去尋找該屬性,而該內(nèi)存區(qū)域也有A和B兩個(gè)部分,如果A部分仍然不存在,則還要從B部分所指向的內(nèi)存區(qū)域去尋找該屬性,直到達(dá)到最頂層的Object類.所以在無形當(dāng)中就形成了一條鏈,也就是我們常說的原型鏈.如果理解了這個(gè)過程我想也就能了解原型對象了.下面簡單分析下b.constructor();的調(diào)用過程便于加深理解.
          1.js會(huì)在b所指向的內(nèi)存區(qū)域A部分讀取constructor屬性.
          2.當(dāng)發(fā)現(xiàn)沒有該屬性后再從其類的構(gòu)造函數(shù)原型對象引用所指向的內(nèi)存區(qū)域讀取該屬性.因?yàn)樵蛯ο笠贸跏紩r(shí)指向一Object對象內(nèi)存區(qū)域(BaseClass.prototype = new Object();)
          3.再從此Object對象的A部分尋找constructor屬性.
          4.沒有找到該屬性則從其類的原型對象即Object.prototype中去尋找constructor.
          5.如果找到該屬性則調(diào)用.
          6.否則,到達(dá)鏈的頂端,返回.
          到此能很清楚的知道js中是如何實(shí)現(xiàn)繼承的,如果我們自定義的類不想繼承自O(shè)bject,則可以修改其prototype的指向,可以讓其指向任意一個(gè)類,這樣也就實(shí)現(xiàn)了繼承自定義類,但js中所有的類都繼承自O(shè)bject類,所以原型鏈的關(guān)系仍然存在.

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

          FeedBack:
          # re: 我所理解的原型對象[未登錄]
          2008-12-07 19:10 | simon
          受教  回復(fù)  更多評論
            
          # re: 我所理解的原型對象
          2010-06-08 12:41 | #
          非常不錯(cuò)  回復(fù)  更多評論
            
          # re: 我所理解的原型對象
          2013-03-12 15:25 | liger 博客園
          非常的好,情不自禁的轉(zhuǎn)了  回復(fù)  更多評論
            

          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 石狮市| 临澧县| 尉氏县| 蛟河市| 大港区| 东安县| 双流县| 星座| 武城县| 汾阳市| 明水县| 张家界市| 道孚县| 吐鲁番市| 彰化县| 石屏县| 腾冲县| 文昌市| 巢湖市| 集贤县| 凉山| 南丹县| 靖安县| 博湖县| 舞阳县| 阿拉善盟| 防城港市| 弋阳县| 叶城县| 铜鼓县| 习水县| 景宁| 大余县| 青神县| 青龙| 芷江| 阿拉善右旗| 巴林左旗| 砀山县| 庆云县| 永春县|