zoukankan      html  css  js  c++  java
  • 如何在Javascript实现OO编程

      http://hi.baidu.com/kxw102/blog/item/10f56239e1c82c2eba998f66.html

    如何在Javascript实现OO编程?恐怕最好的方式就是充分利用prototype属性。关于prototype的介绍有很多,我就不赘述了。比较基本的原理是,当你用prototype编写一个类后,当你new一个新的object,浏览器会自动把prototype中的内容替你附加在object上。这样,通过利用prototype,你也就实现了类似OO的Javascript。

    在Javascript中,object就是一个associative array。一个function就是一个类。当你编写如下function时,其实就是定义了一个类,该function就是它的构造函数。

    function MyObject(name, size)

           {

                  this.name = name;

                  this.size = size;

           }

    之后,你可以方便的通过MyObject类的prototype属性来方便的扩充它。比如,你可以给他添加其他的属性和方法。

           MyObject.prototype.tellSize = function()

           {

                  return "size of "+this.name+" is "+this.size;

           }

          

           MyObject.prototype.color = "red";

           MyObject.prototype.tellColor = function()

           {

                  return "color of "+this.name+" is "+this.color;

           }

          

           var myobj1 = new MyObject("tiddles", "7.5 meters");

           domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

    你可以想象,当你调用tellColor()方法后,结果是这样的:

    color of tiddles is red

    很方便的是,prototype属性可以动态添加。比如,你需要往MyObject中加入一个height属性,并希望其提供一个tellHeight()方法来获得height属性的值。你可以在上面的代码后,继续添加如下的代码:

           MyObject.prototype.height = "2.26 meters";

           MyObject.prototype.tellHeight = function()

           {

                  return "height of "+this.name+" is "+this.height;

           }

    之后,你可以访问一下myobj1的tellHeight()方法,你可以得到如下的结果:

    height of tiddles is 2.26 meters

    prototype的这些动态的特性看起来有些迷人,不过我倒是反而觉得有些凉飕飕的。确实,这些特性给你很大的灵活性,可以给与你runtime改变类属性和方法的能力。不过,稍微发掘一下,会有些不良的习惯产生。

    首先,如果可以动态添加属性和方法,那么很容易让人想到,当我调用时,我想要调用的属性或者方法存在不?这是一个很严肃的问题,如果当我们调用时根本没有该属性或者方法,将可能导致我们的脚本down掉。

    不过也有解决办法。比如,在上面的代码中,当还没有tellHeight()方法时,我们可以如下编写代码避免发生错误:

           if (myobj1.tellHeight)

           {

                  domDiv.innerHTML += myobj1.tellHeight()+"<br /><br />";

           }

    注意,一定要在if语句中,不要加方法后面的那对(),否则,直接就down掉了。有兴趣的读者可以打印一下,看看分别访问myobj1.tellHeight和myobj1.tellHeight()时有什么区别。

    也许,你觉得这个是小意思。加个判断嘛,不就好了?

    对,但是下面一个问题更令人头痛。

    属性和方法在不在的问题简单,可是属性和方法变不变化的问题可就严重了。在不在我们可以检测,变不变呢?比如,请看下面的代码:

           function MyObject(name, size)

           {

                  this.name = name;

                  this.size = size;

           }

          

           MyObject.prototype.color = "red";

           MyObject.prototype.tellColor = function()

           {

                  return "color of "+this.name+" is "+this.color;

           }

          

           var myobj1 = new MyObject("tiddles", "7.5 meters");

           domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

          

           MyObject.prototype.color = "green";

          

           domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

    该代码将产生如下结果:

    color of tiddles is red
    color of tiddles is green

    请注意,你修改的是类MyObject的color属性。但是你惊奇的看到你之前实例化的对象myobj1的属性值竟然也变化了。天!如果你的项目代码是多人合作,那么,也许某个人会在编程时为了图一己之便,擅自修改你的类。于是,所有人的对象都变化了。于是,你们陷入了漫长的debug过程中。。。。。。(不要说我没有告诉你啊)

    上面是属性,还有方法:

           function MyObject(name, size)

           {

                  this.name = name;

                  this.size = size;

           }

          

           MyObject.prototype.color = "red";

           MyObject.prototype.tellColor = function()

           {

                  return "color of "+this.name+" is "+this.color;

           }

          

           var myobj1 = new MyObject("tiddles", "7.5 meters");

           domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

          

           MyObject.prototype.color = "green";

           MyObject.prototype.tellColor = function()

           {

                  return "your color of "+this.name+" is "+this.color;

           }

          

           domDiv.innerHTML += myobj1.tellColor()+"<br /><br />";

    这段代码的结果是:

    color of tiddles is red
    your color of tiddles is green

    哈?原来方法也能变,汗!

    问题来了。Javascript太灵活的编程方式多少让人不适应。如果整个Team的水平都比较高还可以,没人会犯这样的错误。但是,当有个毛头小伙子不知情,擅自修改类,将导致所有的人的对象都发生变化,无论是属性还是方法。在Javascript代码变得越来越多的Ajax时代,这是一个严重的问题。

    这说明,编写Javascript时,好的编程风格更加重要。记得某人曾经说过这样的话,想Java和C#这些比较严格的语言,虽然降低了灵活性,但也减少了犯错误的可能。这样,即使一个新手,他写出的代码也不会与高手差太多。但是,像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 det 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了。

  • 相关阅读:
    计算机网络中的码元的理解
    屏幕扩展,屏幕相对位置的设置
    wireshark使用入门
    Http下载文件的登录验证
    正则-连续相同的单词
    文件系统和数据库索引用B树而不是红黑树的原因
    红黑树的突破点
    Win 10 Revit 2019 安装过程,亲自踩的一遍坑,有你想要的细节
    Java拦截器的实现原理
    根据进程数,资源数判断是否发生死锁
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1775779.html
Copyright © 2011-2022 走看看