面向對象的 JavaScript 編程


    Javascript
對於做過 Web 程序的人不應該是陌生,初期是用來做一些簡單的 FORM 驗證,基本上是在玩弄一些技巧性的東西。 IE 4.0 引入了 DHTML ,同時爲了對抗 Netscape Javascript, 提出了自己的腳本語言 JScript ,除了遵循 EMAC 的標準之外,同時增加了許多擴展,如下要提到的 OOP 編程就是其中的一個,爲了命且概念,我以下提到的 Javascript 都是 Microsoft Internet Explorer 4.0 以上實現的 JScript, 對於 Netscape ,我沒有做過太多的程序,所以一些的區別也就看出來。 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />


    Javascript
不是一個支持面向對象的語言,更加算不上一個開發平臺,但是 Javascript 提供了一個非常強大的基於 prototype 的面向對象調用功能,你可以在你自己需要的地方使用他們。因此 , 如何使用對象?本文儘可能從 Javascript 面向對象實現原理出發,解析清楚它的工作模型。在瞭解這些模型之後,你可以在自己的腳本庫中編寫一些實現代碼,然後在其他地方調用。

 

    Javascript 的語法和 C++ 很接近,不過在類實現中沒有使用關鍵字 Class, 實現繼承的時候也沒有采用傳統的 Public 或者 Implement 等等所謂的關鍵字來標示類的實現。這樣的情況下,可能有就有人會問,如何編寫 Javascript Class ,如何實現繼承。我開始也是百思不得其解,後來看了 MSDN, 才知道採用了 prototype 來實現,包括繼承和重載,也可以通過這個關鍵字來實現。

 

    Javascript 的函數很奇怪,每個都是默認實現了 Optional 的,即參數都可以可選的, function a(var1,var2,var3), 在調用的過程中 a(),a(value1),a(value1,value2) 等等的調用都是正確的,至少在即使編譯部分可以完整通過,至於其它,只是和函數的實現邏輯比較相關了。

    以下就 JS 對於類的實現、繼承、重載詳細介紹其實現方式。

    1 。實現

    Js 類的實現就通過函數直接實現的,每個函數可以直接看成 class ,如下代碼

    function ClassTest1(){

        ...//implement code

    }

    var a=new ClassTest1

   

    function ClassTest2(var1){

        ...//implement code

    }

    var b=new ClassTest("value")

    對於類的屬性,可以通過兩種方式實現

    1 this."<Property or Method" 的方式實現,在類聲明函數中直接給出函數的實現,如 this.Add=new function(strUserName,strPassword) 這樣的方式調用,編寫的方式在 Class Function 中調用。

    2 通過 ClassFunction.prototype.[FunctionName]=function(var1,var2...){//todo} 這樣的方式完成調用。

    這兩種方式從目標來看是一致的,按照我個人的觀點來看,區別的只是在於實現方式,通過 this.propertyName 的方式來創建, Jscript 自動創建了 property 或者 method 的入口,不過從程序的角度而言,還是使用 prototype 的關鍵字實現比較靈活。

   

    另外 Javascript 也可以和我們 C++ 中那種嵌套聲明的方法來聲明 ,C++ 實現的方法如下

    Public Class ClassName:ParentClass{

        Public DataType FunctionName(){

 

        }

        Public Class ClassName{

            Public DataType FunctionName(){

            }

        }

    }

    Javascript 當中,當然不存在 class 這樣的關鍵字了 , 所以實現起來有點戲劇性,不過仍然爲一個非常巧妙的實現。

    function className(){

        //Property Implement

        this.UserName="blue";

        //Method Implement

        this.Add=new function(){

 

        }

        //Sub Class Implement

        function SubClassName(){

            this.PropertyName="hi"           

        }

        //sub class method implement

        SubClassName.prototype.Change=function{

 

        }

    }

    //Main Class Method Implement

    className.prototype.Delete=function(){

 

    }

    如上的代碼大致演示了 Javascript 類中屬性和方法的實現,另外有一點比較困惑,整個 class 中都是 public 的,沒有關鍵字 private 之類的可以控制某些方法是否隱藏,那麼在我們編寫代碼實現的規範中,我看國外一些程序員都是使用 _functionName 這樣子爲函數命的方法來區分,但是在調用過程中實際還可以調用的。

    實現了屬性和方法,剩下的就是 Event 的實現了,我查找了許多資料,包括整個 MSDN 關於 JScript 的參考,都沒有看到一個很好的模型關於事件實現的,後來參考了一些站點編寫 HTA(HTML Component, 有空我會寫一些相關的文章)的實現,藉助於比較扭曲(我個人認爲)的方法可以大致的實現基於事件驅動的功能。大致的思路是這樣子的:

    1 . 將所有的事件定義成屬性,只要簡單的聲明就可以

    2 . 在需要觸發事件的代碼中判斷事件屬性是否是一個函數,如果是函數,直接執行函數代碼,如果是字符串,那麼執行字符串函數,通過 eval(str) 來執行。

    3) . 在類的實例當中註冊事件函數。

    爲了簡單說明如上的思路,採用 timer 這樣簡單的例子來表述如上的所提到的內容,如果只是爲了簡單的實現 timer 的功能, Javascript setInterval 函數就可以滿足全部的要求,如下的代碼只是用來說明 Timer 的工作原理。

//Class For Timer
function Timer(iInterval){
 //if not set the timer interval ,then defalut set to 500ms
 this.Interval=iInterval || 500;
 this._handleInterval;
 this.TimerEvent=null
 function Start(){
  if(this.Interval!=0){
   this._handleInterval=setInterval("TimerCallBack()",this.Interval);
  }
 }
 function Start(){
  clearInterval(this._handleInterval);
 }
 function TimerCallBack(){
  if (typeof this.TimerEvent=="function"){
   this.TimerEvent();
  }
  else if(this.TimerEvent!=null && this.TimerEvent.length>0){
   eval(this.TimerEvent);
  }
 }

//Code for Instance
var t=new Timer(3);

//------------------------------------//

//1.
t.TimerEvent=function(){
//todo
}

//2.
t.TimerEvent="alert(/"hello/")";

//3.

t.TimerEvent=tTimerCall;

//----------------------------------//
t.Start();
t.Stop();

function tTimerCall(){

 

}

 

    實際工作代碼是在 TimerCallBack() 上面實現,事件觸發作爲屬性的方式來實現,在應用實例中,代碼提供了三種方法去調用事件,不過在事件的回調當中,我還沒有想到如何可以帶參數,只有才各自的實現當中訪問各自需要的屬性才能夠實現全部的要求。

 

    2 。繼承。

    剛採用了大篇幅的文字去介紹如何實現 Javascript 的各種實現,也就是從邏輯上完成了一個封裝 class 的實現,從某種意義上來說, class 的實現是真正腳本編程中使用最多的部分,不過如果只是要完成如上的功能,使用 VBScript 來編寫更能更加清晰,畢竟 VBscript 提供了 class 關鍵字,同時提供了 public private 這兩個關鍵字,可以清晰的將公共和私有對象分離,至於事件的實現,也可以採用類似 Javascript 實現的思路,只是對於函數的引用需要採用 GetRef 這個函數,具體的用法可以參考 scripting reference,MSDN 裏頭也有詳細的介紹,而 Javascript 強大至於在於如下要說的了,雖然具體的東西可能不多。

    如上所言,我們已經完成了一個基本的類實現 Timer ,現在要做的是重新編寫這個類,我們簡單的只是想在這個類之中加入一個方法,提供當前的系統時間,方法的名稱爲 getSystemDate, 顯然如果全部重新編寫,那就失去了我這裏說的意義了。先看看如下的實現。

    function NewTimer(iInterval){

        //call super

        this.base=Timer;

        this.base iInterval);       

    }

    NewTimer.prototype=new Timer;

    NewTimer.prototype.getSystemDate=function(){

        var dt=new Date();

        return dt.getYear()+"-"+dt.getMonth()+"-"+dt.getDay()

    }

   

    上述代碼實現了 NewTimer 類,從 Timer 繼承, Javascript 沒有使用 或者 java public 那樣類似的關鍵字,只是通過 newclassname.prototype=new baseclass 這樣的方法來完成,同時 NewTimer 實現了 getSystemDate 的方法,在 NewTimer 的初始化函數中,我使用了 this.base=Timer ,是爲了引用父類的實現,不過在對於父類其他實現函數的調用,到現在我沒有找到一個確定的方法,是否通過 this.base.start() 那樣來調用還是其他的,如果有誰比較清楚的,麻煩告訴我,另外在 netscape 的站點上,我查到有一個特殊的 "__proto__" 的屬性好像是對於父類的直接引用,不過具體的我也沒有嘗試過,在 msdn 中也沒有看到對於 __proto__ 的支持。

   

    3 。重載

    或許這個是 OOP 編程中比較複雜的地方了,在 Javascript 的實現中有點無奈,也就是通過 prototype 的方式來完成的,不過因爲我不清楚如何調用父類的實現函數,那麼在重載中只能夠重新編寫所有的實現了,另外就是在實現中實例化一個父類,然後通過調用它來返回需要的東西。

    Javascript 中所有的對象都是從 Object 繼承下來的, object 提供了 toString() 的方法,也就是說如果調用 alert(objInstance) 這樣的過程,實際上是調用了 alert(objInstance.toString()) 的方法,如果沒有編寫實現, object 默認的 toString() 都是 "object object" 這樣子的,在許多地方需要重載這個函數的,比如 Timer, 如果我們希望 var ins=new Timer(5);alert(ins) 調用得到的是 interval 的值 5 ,那麼就需要重新編寫 toString() 方法了

    Timer.prototype.toString=function(){ return this.Interval};

    以上代碼實現之後 alert(ins) 得到的就是 5 了。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章