隨筆 - 154  文章 - 60  trackbacks - 0
          <2007年10月>
          30123456
          78910111213
          14151617181920
          21222324252627
          28293031123
          45678910

          聲明:

          該blog是為了收集資料,認識朋友,學習、提高技術,所以本blog的內容除非聲明,否則一律為轉載!!

          感謝那些公開自己技術成果的高人們!??!

          支持開源,尊重他人的勞動?。?

          常用鏈接

          留言簿(3)

          隨筆分類(148)

          隨筆檔案(143)

          收藏夾(2)

          其他

          學習(技術)

          觀察思考(非技術)

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          利用共享prototype實現繼承
          繼承是面向對象開發的又一個重要概念,它可以將現實生活的概念對應到程序邏輯中。例如水果是一個類,具有一些公共的性質;而蘋果也是一類,但它們屬于水果,所以蘋果應該繼承于水果。
          在JavaScript中沒有專門的機制來實現類的繼承,但可以通過拷貝一個類的prototype到另外一個類來實現繼承。一種簡單的實現如下:
          fucntion class1(){
                //構造函數
          }

          function class2(){
                //構造函數
          }
          class2.prototype=class1.prototype;
          class2.prototype.moreProperty1="xxx";
          class2.prototype.moreMethod1=function(){
                //方法實現代碼
          }
          var obj=new class2();
          這樣,首先是class2具有了和class1一樣的prototype,不考慮構造函數,兩個類是等價的。隨后,又通過prototype給class2賦予了兩個額外的方法。所以class2是在class1的基礎上增加了屬性和方法,這就實現了類的繼承。
          JavaScript提供了instanceof操作符來判斷一個對象是否是某個類的實例,對于上面創建的obj對象,下面兩條語句都是成立的:
          obj instanceof class1
          obj instanceof class2
          表面上看,上面的實現完全可行,JavaScript也能夠正確的理解這種繼承關系,obj同時是class1和class2的實例。事是上不對,JavaScript的這種理解實際上是基于一種很簡單的策略??聪旅娴拇a,先使用prototype讓class2繼承于class1,再在class2中重復定義method方法:
          <script language="JavaScript" type="text/javascript">
          <!--
          //定義class1
          function class1(){
                //構造函數
          }
          //定義class1的成員
          class1.prototype={
                m1:function(){
                      alert(1);
                }
          }
          //定義class2
          function class2(){
                //構造函數
          }
          //讓class2繼承于class1
          class2.prototype=class1.prototype;
          //給class2重復定義方法method
          class2.prototype.method=function(){
                alert(2);
          }
          //創建兩個類的實例
          var obj1=new class1();
          var obj2=new class2();
          //分別調用兩個對象的method方法
          obj1.method();
          obj2.method();
          //-->
          </script>
          從代碼執行結果看,彈出了兩次對話框“2”。由此可見,當對class2進行prototype的改變時,class1的prototype也隨之改變,即使對class2的prototype增減一些成員,class1的成員也隨之改變。所以class1和class2僅僅是構造函數不同的兩個類,它們保持著相同的成員定義。從這里,相信讀者已經發現了其中的奧妙:class1和class2的prototype是完全相同的,是對同一個對象的引用。其實從這條賦值語句就可以看出來:
          //讓class2繼承于class1
          class2.prototype=class1.prototype;
          在JavaScript中,除了基本的數據類型(數字、字符串、布爾等),所有的賦值以及函數參數都是引用傳遞,而不是值傳遞。所以上面的語句僅僅是讓class2的prototype對象引用class1的prototype,造成了類成員定義始終保持一致的效果。從這里也看到了instanceof操作符的執行機制,它就是判斷一個對象是否是一個prototype的實例,因為這里的obj1和obj2都是對應于同一個prototype,所以它們instanceof的結果都是相同的。
          因此,使用prototype引用拷貝實現繼承不是一種正確的辦法。但在要求不嚴格的情況下,卻也是一種合理的方法,惟一的約束是不允許類成員的覆蓋定義。下面一節,將利用反射機制和prototype來實現正確的類繼承。
          利用反射機制和prototype實現繼承
          前面一節介紹的共享prototype來實現類的繼承,不是一種很好的方法,畢竟兩個類是共享的一個prototype,任何對成員的重定義都會互相影響,不是嚴格意義的繼承。但在這個思想的基礎上,可以利用反射機制來實現類的繼承,思路如下:利用for(…in…)語句枚舉出所有基類prototype的成員,并將其賦值給子類的prototype對象。例如:
          <script language="JavaScript" type="text/javascript">
          <!--
          function class1(){
                //構造函數
          }
          class1.prototype={
                method:function(){
                     alert(1);
                },
                method2:function(){
                     alert("method2");
                }
          }
          function class2(){
                //構造函數
          }
          //讓class2繼承于class1
          for(var p in class1.prototype){
                 class2.prototype[p]=class1.prototype[p];
          }

          //覆蓋定義class1中的method方法
          class2.prototype.method=function(){
                alert(2);
          }
          //創建兩個類的實例
          var obj1=new class1();
          var obj2=new class2();
          //分別調用obj1和obj2的method方法
          obj1.method();
          obj2.method();
          //分別調用obj1和obj2的method2方法
          obj1.method2();
          obj2.method2();
          //-->
          </script>
          從運行結果可見,obj2中重復定義的method已經覆蓋了繼承的method方法,同時method2方法未受影響。而且obj1中的method方法仍然保持了原有的定義。這樣,就實現了正確意義的類的繼承。為了方便開發,可以為每個類添加一個共有的方法,用以實現類的繼承:
          //為類添加靜態方法inherit表示繼承于某類
          Function.prototype.inherit=function(baseClass){
               for(var p in baseClass.prototype){
                      this.prototype[p]=baseClass.prototype[p];
               }
          }
          這里使用所有函數對象(類)的共同類Function來添加繼承方法,這樣所有的類都會有一個inherit方法,用以實現繼承,讀者可以仔細理解這種用法。于是,上面代碼中的:
          //讓class2繼承于class1
          for(var p in class1.prototype){
                 class2.prototype[p]=class1.prototype[p];
          }
          可以改寫為:
          //讓class2繼承于class1
          class2.inherit(class1)
          這樣代碼邏輯變的更加清楚,也更容易理解。通過這種方法實現的繼承,有一個缺點,就是在class2中添加類成員定義時,不能給prototype直接賦值,而只能對其屬性進行賦值,例如不能寫為:
          class2.prototype={
                //成員定義
          }
          而只能寫為:
          class2.prototype.propertyName=someValue;
          class2.prototype.methodName=function(){
                //語句
          }
          由此可見,這樣實現繼承仍然要以犧牲一定的代碼可讀性為代價,在下一節將介紹prototype-1.3.1框架(注:prototype-1.3.1框架是一個JavaScript類庫,擴展了基本對象功能,并提供了實用工具詳見附錄。)中實現的類的繼承機制,不僅基類可以用對象直接賦值給property,而且在派生類中也可以同樣實現,使代碼邏輯更加清晰,也更能體現面向對象的語言特點。

          prototype-1.3.1框架中的類繼承實現機制
          在prototype-1.3.1框架中,首先為每個對象都定義了一個extend方法:
          //為Object類添加靜態方法:extend
          Object.extend = function(destination, source) {
            for(property in source) {
               destination[property] = source[property];
            }
            return destination;
          }
          //通過Object類為每個對象添加方法extend
          Object.prototype.extend = function(object) {
            return Object.extend.apply(this, [this, object]);
          }
          Object.extend方法很容易理解,它是Object類的一個靜態方法,用于將參數中source的所有屬性都賦值到destination對象中,并返回destination的引用。下面解釋一下Object.prototype.extend的實現,因為Object是所有對象的基類,所以這里是為所有的對象都添加一個extend方法,函數體中的語句如下:
          Object.extend.apply(this,[this,object]);
          這一句是將Object類的靜態方法作為對象的方法運行,第一個參數this是指向對象實例自身;第二個參數是一個數組,包括兩個元素:對象本身和傳進來的對象參數object。函數功能是將參數對象object的所有屬性和方法賦值給調用該方法的對象自身,并返回自身的引用。有了這個方法,下面看類繼承的實現:
          <script language="JavaScript" type="text/javascript">
          <!--
          //定義extend方法
          Object.extend = function(destination, source) {
            for (property in source) {
               destination[property] = source[property];
            }
            return destination;
          }
          Object.prototype.extend = function(object) {
            return Object.extend.apply(this, [this, object]);
          }
          //定義class1
          function class1(){
                //構造函數
          }
          //定義類class1的成員
          class1.prototype={
                method:function(){
                     alert("class1");
                },
                method2:function(){
                     alert("method2");
                }

          }
          //定義class2
          function class2(){
                //構造函數
          }
          //讓class2繼承于class1并定義新成員
          class2.prototype=(new class1()).extend({
                method:function(){
                     alert("class2");
                }
          });

          //創建兩個實例
          var obj1=new class1();
          var obj2=new class2();
          //試驗obj1和obj2的方法
          obj1.method();
          obj2.method();
          obj1.method2();
          obj2.method2();
          //-->
          </script>
          從運行結果可以看出,繼承被正確的實現了,而且派生類的額外成員也可以以列表的形式加以定義,提高了代碼的可讀性。下面解釋繼承的實現:
          //讓class2繼承于class1并定義新成員
          class2.prototype=(new class1()).extend({
                method:function(){
                     alert("class2");
                }
          });
          上段代碼也可以寫為:
          //讓class2繼承于class1并定義新成員
          class2.prototype=class1.prototype.extend({
                method:function(){
                     alert("class2");
                }
          });
          但因為extend方法會改變調用該方法對象本身,所以上述調用會改變class1的prototype的值,犯了和以前一樣的錯誤。在prototype-1.3.1框架中,巧妙的利用new class1()來創建一個實例對象,并將實例對象的成員賦值給class2的prototype。其本質相當于創建了class1的prototype的一個拷貝,在這個拷貝上進行操作自然不會影響原有類中prototype的定義了。

          posted on 2007-10-09 09:42 lk 閱讀(5731) 評論(3)  編輯  收藏 所屬分類: ajax&js

          FeedBack:
          # re: JavaScript類的繼承 2007-12-12 00:13 Mic
          不明白執行的時機  請大蝦幫忙啊
          <script language="javascript" type="text/javascript">
          //定義extend方法
          Object.extend=function(destination,source){
          for(var property in source)
          {

          destination[property]=source[property];
          }

          return destination;
          }

          //通過Object類為每個對象添加extend方法
          Object.prototype.extend=function(object){
          return Object.extend.apply(this,[this,object]);
          }

          function class1()
          {

          }

          class1.prototype={
          method:function(){
          alert("class1");
          },
          method2:function(){
          alert("method2");
          }
          }

          function class2(){

          }

          class2.prototype=(new class1()).extend({
          name:"Michael",
          method:function(){
          alert("class2");
          }
          });

          var obj1=new class1();
          var obj2=new class2();

          //實驗obj1和obj2的方法
          obj1.method();
          obj2.method();

          obj1.method2();
          obj2.method2();
          </script>  回復  更多評論
            
          # re: JavaScript類的繼承[未登錄] 2007-12-29 19:43 cy
          第一種方法直接用class2.prototype=new class1();不就避免對class2的prototype進行引用操作了么?
          <script language="JavaScript" type="text/javascript">
          <!--
          //定義class1
          function class1(){
          //構造函數
          }
          //定義class1的成員
          class1.prototype={
          m1:function(){
          alert(1);
          }
          }
          //定義class2
          function class2(){
          //構造函數
          }
          //讓class2繼承于class1
          class2.prototype=new class1();
          //給class2重復定義方法method
          class2.prototype.method=function(){
          alert(2);
          }
          //創建兩個類的實例
          var obj1=new class1();
          var obj2=new class2();
          //分別調用兩個對象的method方法
          obj1.method();
          obj2.method();
          //-->
          </script>
            回復  更多評論
            
          # re: JavaScript類的繼承 2013-10-03 08:07 LinuxTimes
          一種符合C++、Java、Python 等語言習慣的 JavaScript 語言的類繼承實現方式:
          http://www.linuxtimes.cn/2013/10/02/class-inheritance-javascript/

          請指教!  回復  更多評論
            
          主站蜘蛛池模板: 寿光市| 深圳市| 石景山区| 贞丰县| 革吉县| 区。| 闵行区| 海阳市| 潜山县| 神农架林区| 临洮县| 泸溪县| 霞浦县| 育儿| 乐都县| 怀宁县| 澳门| 濮阳县| 合山市| 丹东市| 钟祥市| 轮台县| 敦化市| 莱西市| 垫江县| 华宁县| 定结县| 酉阳| 祥云县| 云南省| 内江市| 思茅市| 钟祥市| 三明市| 高邑县| 黄平县| 莲花县| 乳源| 湘潭县| 开化县| 隆尧县|