面向对象的 JavaScript 编程


    Javascript
对于做过 Web 程序的人不应该是陌生,初期是用来做一些简单的 FORM 验证,基本上是在玩弄一些技巧性的东西。 IE 4.0 引入了 DHTML ,同时为了对抗 Netscape Javascript, 提出了自己的脚本语言 JScript ,除了遵循 EMAC 的标准之外,同时增加了许多扩展,如下要提到的 OOP 编程就是其中的一个,为了命且概念,我以下提到的 Javascript 都是 Microsoft Internet Explorer 4.0 以上实现的 JScript, 对于 Netscape ,我没有做过太多的程序,所以一些的区别也就看出来。


    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 了。

 

 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1926