zoukankan      html  css  js  c++  java
  • 再论面向对象的Javascript编程(http://www.chinaaspx.com/archive/javascript/13417.htm)

    再论面向对象的Javascript编程

    ——对于原文《面向。。。》的补充       

    作者:蓝翼

    联系方式: liuruhong@263.net

    关键字: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这个函数却不执行,不清楚是否是我的代码还有问题,在继承方面,我发现通过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的开发人员有说帮助,至少能够作为一个参考的资料。

           因为本身水平有限,在一些的理解上面可能有些偏差,也希望有人能够给我指出来。

    参考:

    1.  面向对象的JavaScript编程(liuruhong原作)

    http://www.csdn.net/develop/read_article.asp?id=19401

    2.        评“面向对象的JavaScript编程”(hax原作)

    http://www.csdn.net/develop/Read_Article.asp?Id=19485


     

  • 相关阅读:
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第三节 梯度下降法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第二节 线性回归算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (下)实操篇
    萌新向Python数据分析及数据挖掘 第三章 机器学习常用算法 第一节 KNN算法 (上)理解篇
    萌新向Python数据分析及数据挖掘 第二章 pandas 第五节 Getting Started with pandas
    Oracle数据库安装和授权
    c# 如何获取JSON文件以及如何获取Config文件(framework 和 net .Core)
    C#Core查询数据库存储EXCEL文件
    如何在WINDOW系统下编译P12证书制作
  • 原文地址:https://www.cnblogs.com/snowball/p/466874.html
Copyright © 2011-2022 走看看