Script

本类阅读TOP10

·一个简单的javascript菜单
·网站流量统计代码
·可编辑的 HTML JavaScript 表格控件 DataGrid II
·JavaScript通用库(一)
·在网页中控制wmplayer播放器
·层遇到select框时
·TYPEING TEST ON LINE 在线打字测试 Free Software Javascript (aiiiq)
·javascript表单之间的数据传递!
·让网页自动穿上外套
·搜索gb2312汉字在网上的频率

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
评“面向对象的JavaScript编程”一文

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

面向对象的JavaScript编程

作者没有看过netscape的文档,也没有看过ECMAScript(ECMA-262)规范,仅仅看msdn是不能真正懂得javascript的。
下面我来指导一下吧。 :)

> 面向对象的JavaScript编程

JavaScript虽然可以认为是一个对象语言,但是与大家熟悉的c++,java不同。主要的区别在于:
1. js是基于对象的语言,而不是严格的面向对象语言。
2. js的对象是基于原型的。什么是prototype?可以去看看《设计模式》中的prototype模式。
3. js的function是一等公民,js不区分class和object。


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

很多人都仅仅玩弄js技巧,其实是半瓶水的表现。在浏览器中过分卖弄js,却不懂得写noscript标签,这是典型的还没有明白web之道的表现。DHTML这种厂商对抗的东西已经没有什么好说的了,大家自己去看DOM标准吧。顺带说一下,netscape有js的guide和reference,建议真正想深入js的人至少要去看一遍,msdn上对js语言的解说虽然一个版本比一个版本多了,但是始终是不如创造语言的公司说得清楚。或者推荐大家看奥莱理的《js权威指南》,我随手翻过,是有史以来最好的js书之一。

>    Javascript不是一个支持面向对象的语言,更加算不上一个开发平台,但是Javascript提供了一个非常强大的基于prototype的面向对象调用功能,你可以在你自己需要的地方使用他们。因此,如何使用对象?本文尽可能从Javascript面向对象实现原理出发,解析清楚它的工作模型。在了解这些模型之后,你可以在自己的脚本库中编写一些实现代码,然后在其他地方调用。

作者这里说的对的,js本身是脚本语言,而且是依赖于host的语言(根据ecma规范的说法),因此很多人关于js如何如何的说法都是错误的,因为他们说的是dhtml或者dom,总之是浏览器环境,而不是js语言的特性。ms的dhtml可以用于js和vbs,DOM是语言独立的。js本身是单纯的语言,虽然主要以浏览器环境为设计目标,但并不影响他在其它环境中发挥作用。例如可以作为服务器端脚本,比如asp(虽然多数用vbs),或者jsp的一种脚本语言(注意js不是jsp,jsp通常使用java作为脚本语言,但是也可以用其他脚本语言)。“基于prototype的面向对象调用功能”这句话就有问题了。prototype不是调用功能,而是语言的机制。而且“面向对象”的提法也不完全准确。从术语使用上讲,面向对象一般指c++,java,smalltalk等,js只被叫做“基于对象”的,当然我觉得这也不是很重要。

>    Javascript的语法和C++很接近,不过在类实现中没有使用关键字Class,实现继承的时候也没有采用传统的Public或者Implement等等所谓的关键字来标示类的实现。这样的情况下,可能有就有人会问,如何编写Javascript的Class,如何实现继承。我开始也是百思不得其解,后来看了MSDN,才知道采用了prototype来实现,包括继承和重载,也可以通过这个关键字来实现。

js的语法是c一路的(java,c#也是)。不仅是没有关键字class那样,严格来说,js没有类的(当然也没有继承一说了)。但是通俗来说,可以认为,js中有类似“类”的东西。顺带说c++不是“完全”的对象语言,因为缺乏“类对象”,呵呵(不过这是语言的不同设计,未必是缺点)。至于imp,那是接口了,许多语言没有明显接口而用多重继承、虚类、抽象方法来模拟,比如c++。prototype并不只是一个关键字,而是js的特质之一。如何继承,虽然你可以从msdn摸索,不过是事倍功半,还是再劝你直接看netscape的guide,或者mozilla上也有。

>    Javascript的函数很奇怪,每个都是默认实现了Optional的,即参数都可以可选的,function a(var1,var2,var3),在调用的过程中a(),a(value1),a(value1,value2)等等的调用都是正确的,至少在即使编译部分可以完整通过,至于其它,只是和函数的实现逻辑比较相关了。

这没有什么奇怪的,只是js的许多特性(动态类型,没有同名函数……)的结果。补充一个,在function之内,可以用arguments像数组一样操作参数。

>    以下就JS对于类的实现、继承、重载详细介绍其实现方式。
>    1。实现
>    Js类的实现就通过函数直接实现的,每个函数可以直接看成class,如下代码

应该这样说,js没有类,但是js中,一切都是对象,包括函数。因此类可以通过做一个构造函数(注意,构造函数是来构造对象而不是构造类的)来模拟。

>    对于类的属性,可以通过两种方式实现
>    2)通过ClassFunction.prototype.[FunctionName]=function(var1,var2...){//todo}这样的方式完成调用。

先纠正用词,这里不是调用而是赋值。

>    这两种方式从目标来看是一致的,按照我个人的观点来看,区别的只是在于实现方式,通过this.propertyName的方式来创建,Jscript自动创建了property或者method的入口,不过从程序的角度而言,还是使用prototype的关键字实现比较灵活。

这两种方法效果基本一致,但是还是有比较重要的区别,即前者是在构造函数里赋值,后者则是从外部通过原型对象赋值。如果有比较复杂的“类层次”,你就会发现两者的不同,还有顺序问题了 :) 后者是更灵活,不过要知道js是完全动态的语言,你甚至可以动态改变constructor,呵呵。

>    另外Javascript也可以和我们C++中那种嵌套声明的方法来声明,C++实现的方法如下
>    在Javascript当中,当然不存在class这样的关键字了,所以实现起来有点戏剧性,不过仍然为一个非常巧妙的实现。
>    function className(){
>        //Property Implement
>        this.UserName="blue";
>        //Method Implement
>        this.Add=new function(){
                  ^^^
              作者一个小笔误,这个new是多余的。
 
>        }
>        //Sub Class Implement
>        function SubClassName(){
>            this.PropertyName="hi"           
>        }
>

顺带说一下,作者过分使用了object.prototype.prop = value 的方法,这其实并不好。因为这破坏了“类”的结构。除了直接赋值原型对象来模拟继承,如无必要,不应使用。

>    如上的代码大致演示了Javascript类中属性和方法的实现,另外有一点比较困惑,整个class中都是public的,没有关键字private之类的可以控制某些方法是否隐藏,那么在我们编写代码实现的规范中,我看国外一些程序员都是使用_functionName这样子为函数命的方法来区分,但是在调用过程中实际还可以调用的。

public之类的,只是为了增加语言的可靠性,对于脚本语言来说,并不是必须。

>    实现了属性和方法,剩下的就是Event的实现了,我查找了许多资料,包括整个MSDN关于JScript的参考,都没有看到一个很好的模型关于事件实现的,后来参考了一些站点编写HTA(HTML Component,有空我会写一些相关的文章)的实现,借助于比较扭曲(我个人认为)的方法可以大致的实现基于事件驱动的功能。大致的思路是这样子的:
>    1).将所有的事件定义成属性,只要简单的声明就可以
>    2).在需要触发事件的代码中判断事件属性是否是一个函数,如果是函数,直接执行函数代码,如果是字符串,那么执行字符串函数,通过eval(str)来执行。
>    3) .在类的实例当中注册事件函数。

这一部分不作评论,自己去看DOM 2的事件模型。

>    2。继承。
>    刚采用了大篇幅的文字去介绍如何实现Javascript的各种实现,也就是从逻辑上完成了一个封装class的实现,从某种意义上来说,class的实现是真正脚本编程中使用最多的部分,不过如果只是要完成如上的功能,使用VBScript来编写更能更加清晰,毕竟VBscript提供了class关键字,同时提供了public 和private这两个关键字,可以清晰的将公共和私有对象分离,至于事件的实现,也可以采用类似Javascript实现的思路,只是对于函数的引用需要采用GetRef这个函数,具体的用法可以参考scripting reference,MSDN里头也有详细的介绍,而Javascript强大至于在于如下要说的了,虽然具体的东西可能不多。

关于vbs我只说一句:vbs是M$牌的垃圾。

>    上述代码实现了NewTimer类,从Timer继承,Javascript没有使用“:”或者java的public那样类似的关键字,只是通过newclassname.prototype=new baseclass这样的方法来完成,同时NewTimer实现了getSystemDate的方法,在NewTimer的初始化函数中,我使用了this.base=Timer,是为了引用父类的实现,不过在对于父类其他实现函数的调用,到现在我没有找到一个确定的方法,是否通过this.base.start()那样来调用还是其他的,如果有谁比较清楚的,麻烦告诉我,另外在netscape的站点上,我查到有一个特殊的"__proto__"的属性好像是对于父类的直接引用,不过具体的我也没有尝试过,在msdn中也没有看到对于__proto__的支持。

之所以不是像其他语言那样继承,那是因为这根本不是“真正”的继承,因为js根本没有“真正”的类,呵呵。prototype的实质就是对原型对象的一个引用。至于调用“父类”方法,其实很简单,在调用了“父类”的构造函数之后直接调用就是了。至于为什么用this.base=parent,其实想明白一件事情就很简单了。parent实际上并不是类,而是构造函数。在“子类”构造函数内部,当时还没有原型存在(prototype是外部动态赋值的,不是静态信息)。所以必须手动的获取“父类”构造函数,运行一下。

也许有人要问,那既然子类直接运行父类构造函数,干吗还要原型?把所有东西写在构造函数不就结了?嘿嘿,想想作者的“第二种方法”。prototype有个特性,给原型增加一个属性(包括方法),所有继承这个原型的对象都会自动添加这个属性。因此,如果你要用这个特性,还是需要原型的。至少你可以用instanceOf操作符来判断变量的类型。

__proto__可以被检测和回溯,从而形成一个原型链,这在比较复杂的“类结构”里是有用的,你可以用它来写自己的instanceOf。不过这不是ecma规范要求的,也应该仅仅在语言内部使用(你真的需要在子类里去动态改变父类?)。

>    3。重载
>    或许这个是OOP编程中比较复杂的地方了,在Javascript的实现中有点无奈,也就是通过prototype的方式来完成的,不过因为我不清楚如何调用父类的实现函数,那么在重载中只能够重新编写所有的实现了,另外就是在实现中实例化一个父类,然后通过调用它来返回需要的东西。

这个无奈只是作者杞人忧天 :)
实例化一个父类对象没有什么大不了的,不要拘泥于“正统”的OO观念。想想看,在原型继承的时候,你实际上不正是实例化一个父类对象,然后赋值给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()方法了

除了toString,你也可以重写valueOf用来给你的对象返回一个原生类型的值,呵呵。

>    长篇累牍的说了一堆废话,终于说玩了大致的想法,其实语言只是一个实现工具,重要的在于设计的思想,不妨可以考虑一下,在BITI内部开发一个OpenSource的Project,如果是基于javascript的模型来建立开发平台库,我希望有人可以参与。通过javascript建立一系列基于Web UI的控件,目前我在开发过程中也是立足于上述的想法。另外,附上我去年写的类似HotMail的按钮那样的class源程序,暂时还没有使用Image Preload,希望有人可以帮我修改一下,如果需要可以运行的版本,给我发送Email:liuruhong@263.net。另外有空我会写基于Javascript的组件编程和多媒体编程部分,再下来就是XML方面了,希望大家共同进步。

语言是工具,有不同的应用目标。设计思想当然可以共通,特别是对象语言。你大可以用js快速开发一个原型(一般意义上的原型,不是前面的技术术语),然后用java, c++作最终成品。至于用js写webUI,我要稍微泼一点点冷水,不必太过在意。webUI的问题主要不在于js,而在于浏览器本身和其他技术标准。比如mozilla的UI用XUL语言来写的。而且许多人认为XBL和HTC(都是用js来封装web控件)等不是很好的方向(虽然我一度挺喜欢这两种技术),因为没有很好的正交分解,把样式、js等都混淆了。未来的方向还是要靠w3c这个标准化组织给出。所以用js也不必写很复杂的类结构(毕竟脚本语言是要给人们轻松的),更多精力花在DOM和兼容性上吧。

最后说一下,netscape还在继续开发js 2.0(好几年了),ecma也跟着同时作edition 4(M$就不清楚其动向,而且其jscript还没有完全实现edition 3),这个版本里好像加入了class,public等关键字,可能会有很大的变化。有兴趣的人可以去看:http://www.mozilla.org/js/language/js20/index.html




相关文章

相关软件




月光软件程序下载编程文档电脑教程网站设计网址导航网络文学游戏天地幽默笑话生活休闲写作范文安妮宝贝
电脑技术编程开发网络专区谈天说地情感世界游戏元素分类游戏热门游戏体育运动手机专区业余爱好影视沙龙
音乐天地数码广场教育园地科学大观古今纵横谈股论金人文艺术医学保健动漫图酷二手专区地方风情各行各业

月光软件站·版权所有