class="MsoNormal" style="MARGIN: 0cm 0cm 0pt; TEXT-ALIGN: left" align="left">
Javascript 对于做过 Web 程序的人不应该是陌生,初期是用来做一些简单的 FORM 验证,基本上是在玩弄一些技巧性的东西。 IE 4.0 引入了 DHTML ,同时为了对抗 Netscape 的 Javascript, 提出了自己的脚本语言 JScript ,除了遵循 EMAC 的标准之外,同时增加了许多扩展,如下要提到的 OOP 编程就是其中的一个,为了命且概念,我以下提到的 Javascript 都是 Microsoft Internet Explorer 4.0 以上实现的 JScript, 对于 Netscape ,我没有做过太多的程序,所以一些的区别也就看出来。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
Javascript 不是一个支持面向对象的语言,更加算不上一个开发平台,但是 Javascript 提供了一个非常强大的基于 prototype 的面向对象调用功能,你可以在你自己需要的地方使用他们。因此 , 如何使用对象?本文尽可能从 Javascript 面向对象实现原理出发,解析清楚它的工作模型。在了解这些模型之后,你可以在自己的脚本库中编写一些实现代码,然后在其他地方调用。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Javascript 的语法和 C++ 很接近,不过在类实现中没有使用关键字 Class, 实现继承的时候也没有采用传统的 Public 或者 Implement 等等所谓的关键字来标示类的实现。这样的情况下,可能有就有人会问,如何编写 Javascript 的 Class ,如何实现继承。我开始也是百思不得其解,后来看了 MSDN, 才知道采用了 prototype 来实现,包括继承和重载,也可以通过这个关键字来实现。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Javascript 的函数很奇怪,每个都是默认实现了 Optional 的,即参数都可以可选的, class="tags" href="/tags/FUNCTION.html" title=function>function a(var1,var2,var3), 在调用的过程中 a(),a(value1),a(value1,value2) 等等的调用都是正确的,至少在即使编译部分可以完整通过,至于其它,只是和函数的实现逻辑比较相关了。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 以下就 JS 对于类的实现、继承、重载详细介绍其实现方式。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 1 。实现
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Js 类的实现就通过函数直接实现的,每个函数可以直接看成 class ,如下代码
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> class="tags" href="/tags/FUNCTION.html" title=function>function ClassTest1(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> ...//implement code
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> var a=new ClassTest1
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> class="tags" href="/tags/FUNCTION.html" title=function>function ClassTest2(var1){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> ...//implement code
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> var b=new ClassTest("value")
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 对于类的属性,可以通过两种方式实现
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 1 ) this."<Property or Method" 的方式实现,在类声明函数中直接给出函数的实现,如 this.Add=new class="tags" href="/tags/FUNCTION.html" title=function>function(strUserName,strPassword) 这样的方式调用,编写的方式在 Class Function 中调用。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 2 )通过 ClassFunction.prototype.[FunctionName]=class="tags" href="/tags/FUNCTION.html" title=function>function(var1,var2...){//todo} 这样的方式完成调用。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 这两种方式从目标来看是一致的,按照我个人的观点来看,区别的只是在于实现方式,通过 this.propertyName 的方式来创建, Jscript 自动创建了 property 或者 method 的入口,不过从程序的角度而言,还是使用 prototype 的关键字实现比较灵活。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 另外 Javascript 也可以和我们 C++ 中那种嵌套声明的方法来声明 ,C++ 实现的方法如下
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Public Class ClassName:ParentClass{
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Public DataType FunctionName(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Public Class ClassName{
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Public DataType FunctionName(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 在 Javascript 当中,当然不存在 class 这样的关键字了 , 所以实现起来有点戏剧性,不过仍然为一个非常巧妙的实现。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> class="tags" href="/tags/FUNCTION.html" title=function>function className(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //Property Implement
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> this.UserName="blue";
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //Method Implement
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> this.Add=new class="tags" href="/tags/FUNCTION.html" title=function>function(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //Sub Class Implement
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> class="tags" href="/tags/FUNCTION.html" title=function>function SubClassName(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> this.PropertyName="hi"
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //sub class method implement
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> SubClassName.prototype.Change=class="tags" href="/tags/FUNCTION.html" title=function>function{
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //Main Class Method Implement
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> className.prototype.Delete=class="tags" href="/tags/FUNCTION.html" title=function>function(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 如上的代码大致演示了 Javascript 类中属性和方法的实现,另外有一点比较困惑,整个 class 中都是 public 的,没有关键字 private 之类的可以控制某些方法是否隐藏,那么在我们编写代码实现的规范中,我看国外一些程序员都是使用 _class="tags" href="/tags/FUNCTION.html" title=function>functionName 这样子为函数命的方法来区分,但是在调用过程中实际还可以调用的。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 实现了属性和方法,剩下的就是 Event 的实现了,我查找了许多资料,包括整个 MSDN 关于 JScript 的参考,都没有看到一个很好的模型关于事件实现的,后来参考了一些站点编写 HTA(HTML Component, 有空我会写一些相关的文章)的实现,借助于比较扭曲(我个人认为)的方法可以大致的实现基于事件驱动的功能。大致的思路是这样子的:
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 1 ) . 将所有的事件定义成属性,只要简单的声明就可以
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 2 ) . 在需要触发事件的代码中判断事件属性是否是一个函数,如果是函数,直接执行函数代码,如果是字符串,那么执行字符串函数,通过 eval(str) 来执行。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 3) . 在类的实例当中注册事件函数。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 为了简单说明如上的思路,采用 class="tags" href="/tags/TIMER.html" title=timer>timer 这样简单的例子来表述如上的所提到的内容,如果只是为了简单的实现 class="tags" href="/tags/TIMER.html" title=timer>timer 的功能, Javascript 中 setInterval 函数就可以满足全部的要求,如下的代码只是用来说明 Timer 的工作原理。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//Class For Timer
class="tags" href="/tags/FUNCTION.html" title=function>function Timer(iInterval){
//if not set the class="tags" href="/tags/TIMER.html" title=timer>timer interval ,then defalut set to 500ms
this.Interval=iInterval || 500;
this._handleInterval;
this.TimerEvent=null
class="tags" href="/tags/FUNCTION.html" title=function>function Start(){
if(this.Interval!=0){
this._handleInterval=setInterval("TimerCallBack()",this.Interval);
}
}
class="tags" href="/tags/FUNCTION.html" title=function>function Start(){
clearInterval(this._handleInterval);
}
class="tags" href="/tags/FUNCTION.html" title=function>function TimerCallBack(){
if (typeof this.TimerEvent=="class="tags" href="/tags/FUNCTION.html" title=function>function"){
this.TimerEvent();
}
else if(this.TimerEvent!=null && this.TimerEvent.length>0){
eval(this.TimerEvent);
}
}
}
//Code for Instance
var t=new Timer(3);
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//------------------------------------//
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//1.
t.TimerEvent=class="tags" href="/tags/FUNCTION.html" title=function>function(){
//todo
}
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//2.
t.TimerEvent="alert(/"hello/")";
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//3.
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">t.TimerEvent=tTimerCall;
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">//----------------------------------//
t.Start();
t.Stop();
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">class="tags" href="/tags/FUNCTION.html" title=function>function tTimerCall(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">}
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt 36pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 实际工作代码是在 TimerCallBack() 上面实现,事件触发作为属性的方式来实现,在应用实例中,代码提供了三种方法去调用事件,不过在事件的回调当中,我还没有想到如何可以带参数,只有才各自的实现当中访问各自需要的属性才能够实现全部的要求。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 2 。继承。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 刚采用了大篇幅的文字去介绍如何实现 Javascript 的各种实现,也就是从逻辑上完成了一个封装 class 的实现,从某种意义上来说, class 的实现是真正脚本编程中使用最多的部分,不过如果只是要完成如上的功能,使用 VBScript 来编写更能更加清晰,毕竟 VBscript 提供了 class 关键字,同时提供了 public 和 private 这两个关键字,可以清晰的将公共和私有对象分离,至于事件的实现,也可以采用类似 Javascript 实现的思路,只是对于函数的引用需要采用 GetRef 这个函数,具体的用法可以参考 scripting reference,MSDN 里头也有详细的介绍,而 Javascript 强大至于在于如下要说的了,虽然具体的东西可能不多。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 如上所言,我们已经完成了一个基本的类实现 Timer ,现在要做的是重新编写这个类,我们简单的只是想在这个类之中加入一个方法,提供当前的系统时间,方法的名称为 getSystemDate, 显然如果全部重新编写,那就失去了我这里说的意义了。先看看如下的实现。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> class="tags" href="/tags/FUNCTION.html" title=function>function NewTimer(iInterval){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> //call super
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> this.base=Timer;
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> this.base ( iInterval);
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> NewTimer.prototype=new Timer;
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> NewTimer.prototype.getSystemDate=class="tags" href="/tags/FUNCTION.html" title=function>function(){
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> var dt=new Date();
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> return dt.getYear()+"-"+dt.getMonth()+"-"+dt.getDay() ;
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> }
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 上述代码实现了 NewTimer 类,从 Timer 继承, Javascript 没有使用 “ : ” 或者 java 的 public 那样类似的关键字,只是通过 newclassname.prototype=new baseclass 这样的方法来完成,同时 NewTimer 实现了 getSystemDate 的方法,在 NewTimer 的初始化函数中,我使用了 this.base=Timer ,是为了引用父类的实现,不过在对于父类其他实现函数的调用,到现在我没有找到一个确定的方法,是否通过 this.base.start() 那样来调用还是其他的,如果有谁比较清楚的,麻烦告诉我,另外在 netscape 的站点上,我查到有一个特殊的 "__proto__" 的属性好像是对于父类的直接引用,不过具体的我也没有尝试过,在 msdn 中也没有看到对于 __proto__ 的支持。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 3 。重载
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 或许这个是 OOP 编程中比较复杂的地方了,在 Javascript 的实现中有点无奈,也就是通过 prototype 的方式来完成的,不过因为我不清楚如何调用父类的实现函数,那么在重载中只能够重新编写所有的实现了,另外就是在实现中实例化一个父类,然后通过调用它来返回需要的东西。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Javascript 中所有的对象都是从 Object 继承下来的, object 提供了 toString() 的方法,也就是说如果调用 alert(objInstance) 这样的过程,实际上是调用了 alert(objInstance.toString()) 的方法,如果没有编写实现, object 默认的 toString() 都是 "object object" 这样子的,在许多地方需要重载这个函数的,比如 Timer, 如果我们希望 var ins=new Timer(5);alert(ins) 调用得到的是 interval 的值 5 ,那么就需要重新编写 toString() 方法了
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> Timer.prototype.toString=class="tags" href="/tags/FUNCTION.html" title=function>function(){ return this.Interval};
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt"> 以上代码实现之后 alert(ins) 得到的就是 5 了。
class="MsoNormal" style="MARGIN: 0cm 0cm 0pt">