再論物件導向的Javascript編程

來源:互聯網
上載者:User

關鍵字:Javascript OOP 物件導向 Jscript 原型 prototype

提要:

       在原先《物件導向的JavaScript編程》中,筆者提出了通過Javascript(確切意義上面來說是Microsoft的Jscript)來實現OOP的思想,原文中因為筆者知識的局限,存在一些沒有理清楚的思路,感謝一些網友提供的評論,結合這段時間的實際工作,筆者修正了原文中的一些想法.

 

       因為個人知識水平有限的原因,以下所提到的JavaScript僅僅止於Microsoft 的Jscript,至於和NetScape之間的一些不同,也僅止於筆者所知道的範圍。在原文中筆者提出了物件導向的JavaScript的概念,不是希望在賣弄Script的技巧,只是覺得在開發的過程中或多或少的會用到,因此從個人的角度提出一些相對可行性的建議。

 

       原文對於Javascript提出了實現,封裝,繼承,重載,事件等等各個概念,因為個人理解的偏差,原文中有許多地方不甚貼切之處,因此本文只是對於原文的一些個人看法的一些修正。

 

       Javascript從OOP的角度來說,應該不是一門純OOP的語言,更加準確來說,是一門Object-Based的指令碼語言,因此原文提到的所謂類的概念,只是從傳統OOP語言的角度去描述的,而所謂的類實現,應該是一種原型實現方式,因為在整個實現的過程中prototype是一個最重要的體現。

 

       理論上來說,所有的function都是object,因此類的建立可以完全基於Object來實現的,原文採用function只是為了更好的實現一些功能,以下就實現,封裝,繼承,重載,事件這5個概念作一些具體的闡述。

      

1.   實現。

Javascript的function是一等公民(hax原語),因此採用function來實現是最好的方式,至於採用如下兩段代碼來實現這個就是根據個人編程的習慣來決定,而一些實現的偏差我會在下文詳細的描述。

 

代碼1

function MyObject(sName){

    this.name=sName;

    this.MessageBox=function(){

           alert("名字"+ this.name);

    }

    this.ChangeName=ChangeName;

    function ChangeName(){

           this.name="改變" + this.name;

    }

}

 

 代碼2

 

function MyObject(sName){

       this.name=sName;

}

MyObject.prototype.MessageBox=function(){

       alert("名字"+ this.name);

}

MyObject.prototype.ChangeName=function(){

       this.name="改變" + this.name;

}

 

採用標準的類實現結構和原型實現方式,在使用來說是沒有區別的,如果從傳統的類設計如(C++,smalltalk那樣的語言)來說,應該採用第一種方案,但是就我個人而言,我建議使用第二種方案,畢竟在開發的過程中,那樣的編寫方式和Javascript的編寫方式比較接近,基本立足於function的實現。

 

2.封裝

      既然引入了對象的概念,必然需要考慮到封裝,C++這樣的語言中有提出private ,protected,public的概念,在Javascript中,沒有對應protected的概念,但是在private和public能夠做到隱含的實現,另外如果需要大量使用到私人變數,實現方式中採用方案一可能更加合適一點,如下代碼所示。

 

function MyObject(sName){

       var mVar=1;

       this.name=sName;

       this.MessageBox=function(){

              alert("名字"+ this.name);

              mVar=2;

       }

       this.ChangeName=ChangeName;

       function ChangeName(){

              this.name="改變" + this.name;

       }

       this.GetVar=function(){

              return mVar;

       }

}

 

mVar是一個私人變數,name是一個共有變數,在MyObject內部實現的函數,可以訪問mVar變數,而name則可以通過this.name的方式在任何實現的地方訪問,對於內建函式的處理,ChangeName是不可以被直接存取的,但是可以通過Object.ChangeName()訪問,這些概念在hax的評論中有幾個網友講述的比較詳細.

 

簡單而言,Javascript提供了對象中的private和public,但是並不提供顯式聲明,在類函數(姑且讓我如此稱呼)中定義的函數和變數都是私人變數,通過this.methodName或者this.varName定義的都是public實現的,通過object.prototype.name實現的也是public,在類函數中的私人函數可以訪問那些私人變數和函數的,至於通過object.prototype.name那樣實現的方法是否可以訪問私人變數,我沒有做過,如果誰做過,麻煩告訴我。

 

在VBS中提出了class的概念,如下的代碼能夠完整地體現封裝的風格。

Class MyClass

       Private vLoginID

       Public UserName

       Public Property Get LoginID

        LoginID=vLoginID

       End Propertyp

       Public Property Let LoginID(vValue)

              vLoginID=vValue

       End Property

End Class

 

在Javascript中沒有顯式所謂屬性概念,這點上面VBS的封裝確實比較乾淨,JavaScript

中沒有這樣的概念,但是可以採用和Java類似的設計方法,如Get_PropertyName,Set_PropertyName這樣的方法來做。我個人建議就採用函數來實現,如果如果帶參數,則表示進行set操作,如果不帶參數,可以認為是get操作。簡單而言採用如下的代碼風格。

Object.prototype.UserName=function(vValue){

    If(vValue){

           //todo get

    }

    Else{

           Return value;

    }

}

       以上提及的只是我個人實現的觀點。

3.繼承

       原文中提到通過設定原型的方式可以實現繼承,就是通過SubObject.prototype=new BaseObject這樣的方式來實現,至於對應的建構函式,在原文中採用了

This.base=parentclass;

This.base();

 

這樣的方式實際是調用父類的建構函式來完成的,完成prototype(原型)設定之後,通過SubObject執行個體化的對象就可以訪問父類的所有方法。在實際開發過程中碰到如下的問題,本來考慮到實現的時候通過方案一和方案二是沒有任何區別的,可是如下的代碼卻有點奇怪。

function son(sName){

       this.base=MyObject;

       this.base(sName);

      

}

 

son.prototype.MessageBox=function(){

       //this.base.MessageBox();

       alert("子類調用");

}

son.prototype.hi=function(){

       alert("kk");

}

var o=new son("hello");

o.MessageBox();

 

最後的執行結果是上文MyObject.MessageBox的方法,son.prototype.MessageBox這個函數卻不執行,不清楚是否是My Code還有問題,在繼承方面,我發現通過this.method=functionName和object.prototype.methodName實現似乎不是完全一樣的,對於這個方面如果有誰比較理解,麻煩告訴我。

 

在剛才的代碼中不使用prototype就可以完成繼承,這裡採用的方法應該是建構函式初始化,因此Object.MessageBox等等一些函數都完全初始化,而如果沒有寫SubObject.prototype=BaseObject,那麼BaseObject.prototype.methodName來實現的一些方法就無法實現。

 

4.重載

在原文中我提到使用Object.prototype.MethodName的方式來重寫方法,但是同時保留了一個問題,就是如何調用父類的方法,上文提到的this.base=MyObject,this.base()這樣只能夠實現建構函式的實現的一些方法,也就是父類在函數體內本身定義的一些方法或者屬性,通過原型prototype實現的就無法實現,在採用SubObject.prototype=new BaseObject那樣的方式,也會出現一些上文提到的一些問題。

在Jscript 5.5以上版本,有一個call函數,通過這個函數我們可以完整的實現對於父類的方法調用,就如同Java裡頭的super,也就可以實現重載。如果讀者的用戶端系統是IE6或者WinME,就已經是Jscript5.5以上版本,至於XP或者2003我就不用多說了,Jscript引擎版本比較低的我建議下載高版本的。

BaseObject

-------------------

function BaseObject(){

     this.msg=null

}

BaseObject.prototyp.Message(msg){

 this.msg=msg;

 alert(this.msg);

 this.msg="change"+this.msg;

}

 

SubObject

function SubObject(){

   BaseObject.call(this);

}

SubObject.prototype=new BaseObject;

SubObject.prototype.Message=function(msg){

    BaseObject.prototype.Message.call(this,msg);

    alert(this.msg);

}

 

 調用代碼

Var v= new SubObject();

v.Message(“hello”);

 

對於父類的方法通過call去調用,call(this,args)表示當前執行個體調用,在SubObject中,BaseObject.call(this)調用父類的方法,在重載Message函數的時候,為了維繫原有的功能,首先調用父類的Message方法,然後才編寫自己的實現代碼。

 

從代碼中大家可以明顯看到是使用BaseObject.prototype.MethodName.call(this,args)這樣的方法調用的,因為使用到了call函數,所以需要比較高版本的支援。

 

以上我討論的是針對Jscript的實現,至於在別的引擎如NetScape或者Flash Script中,可以通過__proto__這個來返回父類的原型,因此調用上就簡單許多,this._proto__相當於Java裡頭的super,在這裡可以直接調用。

 

在低版本的Jscript引擎中我不知道是否可以通過instanceOf或者別的函數來共同實現,這也希望大家來共同探討。

 

5.事件

      本來,在OOP編程中,我不應該討論如此的問題,但是在實際的應用中可能需要使用到類似事件的形式,因此在原文中,基本是採用了類似C++中虛函數的方法,不過在定義的時候只是使用了一個普通變數的方法。

 

       如果類本身是和dom綁定的,對於HTML可以使用fireEvent函數來引發一些事件,不過這些應該已經屬於DHTML討論的東西了。

 

       Javascript本身上來說沒有所謂真正意義上面的物件導向,原文和本文提及的也只是正對實際開發工作中的一些邏輯實現,在瀏覽器內部確實不是適合大量的使用OOP的東西,但是對於Jscript Library開發人員來說,物件導向確實能夠提供不少的好處,筆者寫本文的目的也是希望能夠對於Jscript Library的開發人員有說協助,至少能夠作為一個參考的資料。

 

       因為本身水平有限,在一些的理解上面可能有些偏差,也希望有人能夠給我指出來。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.