在Microsoft AJAX Library下JavaScript的面向对象开发

      Javascript对于做过Web程序的人不应该是陌生,初期是用来做一些简单的FORM验证,基本上是在玩弄一些技巧性的东西。Javascript不是一个支持面向对象的语言,更加算不上一个开发平台,但是Javascript提供了一个非常强大的基于Prototype的面向对象调用功能,这使得我们可以在自己需要的地方使用他们。ASP.NET AJAX中也提供了对JavaScript面向对类型系统的支持。

    在面向对象的语言(如C#,Java)里,命名空间、类、接口、方法等等这些对大家都不陌生,那么你是否在客户端使用过JavaScript来写过基于面向对象的程序呢?详细请看下面分解:

一、命名空间
     命名空间是什么?命名空间的作用是合理的组织大量的类型,使开发人员能够方便的找到他们所需要的类型。如大多数面向对象语言一样,JavaScript在基于Prototype的基础上提供了注册命名空间的方法,见下语法:
Type.registerNamespace("MyNamespae");
   
     比如我们要注册一个为"com.cnblogs.beniao"的命名空间,则使用如下代码进行定义:
1//注册命名空间
2Type.registerNamespace("com.cnblogs.beniao");

    在实际的开发中,命名空间是可以重复注册的,最好是在每个独立的脚本模块前都要注册命名空间以保证命名空间存在.

二、类
      在面向对象的程序语言里,对类的定义为是具有相同属性、操作、关系的对象集合的总称。那在客户端JavaScript里呢?我想也不外于此,只不过不同于面向对象语言里那样通过class来定义,它有专用注册的语法,见下:
1注册一个类
2Type.registerClass("TypeName");
  
     比如要注册一个名为"com.cnblogs.beniao.Employee"的类,""com.cnblogs.beniao"为命名空间注册代码如下:
1//注册一个com.cnblogs.beniao.Employee类
2Type.registerClass("com.cnblogs.beniao.Employee");

      一个类可看作为是抽象出的一个对象,他应该带有构造方法,成员字段以及相关操作,这在面向对象的程序设计里是常见的,而这一特性在客户端JavaScript里也不例外,在JavaScript基于Prototype的支持下也可以为JavaScrpt所注册的类提供构造器和成员字段和相关操作,看看下面的分析:
      ● 定义构造函数
      在JavaScript中类的构造函数使用function定义,同面向对象语言(如C#)一样,构造函数通常用于初始化域变量。面向对象程序语言里定义构造函数,函数名必须与类同名,且函数没有返回值。那JavaScript又是如何定义的呢?定义语法如下:
1//定义构造方法
2MyNamespae.ClassName = function(param1,param2.)
3{
4  this._param1 = param1;
5  this._param2 = param2;
6  
7}

      我们还是从实际的例子出发,来学习和应用各个知识点,现在需要定义一个带有参数的构造方法,并通过构造方法设置成员字段的值(在"com.cnblogs.beniao.Employee"类里),如下:
1//定义构造方法
2com.cnblogs.beniao.Employee = function(name)
3{
4  //如果传递过来的参数为空则设置一默认值
5  this._name = name?name:"beniao";
6}

     ● 定义类的成员(方法,属性,事件)
     在上面定义类的构造方法的示例中就已经使用了类的成员的定义,在定义类的私有成员的时候需要使用下划线开头,定义格式如下:
1//定义类的私有成员
2this._myPrivateField=value;

     如上面定义类的构造方法的时候使用到的成员this._name,例如我们需要定义一个JavaScript类Books,为其定义BookName,BookAuthor,BookPrice三个私有成员,则应该使用如下定义:
1//在Books类里定义了三个成员
2com.cnblogs.beniao.Books = function()
3{
4   this._BookName;
5   this._BookAuthor;
6   this._BookPrice;
7}

     ● 定义类的属性
     面向对象的程序语言里可以为成员字段定义属性,JavaScript也不例外,它也可以为成员定义诸如get,set的属性访问器,只是使用function基于Prototype来进行定义,就上面Books类而言,现在我们对其增加属性访问器,则如下:
 1//定义成员
 2com.cnblogs.beniao.Book = function()
 3{
 4   this._BookName;
 5   this._BookAuthor;
 6   this._BookPrice;
 7}

 8
 9//定义属性
10com.cnblogs.beniao.Book.prototype=
11{
12   get_BookName : function()
13   {
14      return this._BookName;
15   }
,
16   set_BookName : function(value)
17   {
18      this._BookName=value;
19   }
,
20   get_BookAuthor : function()
21   {
22      return this._BookAuthor;
23   }
,
24   set_BookAuthor : function(value)
25   {
26      this._BookAuthore=value;
27   }
,
28   get_BookPrice : function()
29   {
30      return this._BookPrice;
31   }
,
32   set_BookPrice : function(value)
33   {
34      this._BookPrice=value;
35   }

36}

     ●  定义方法(抽象方法)
     本文从开始到现在已经介绍了命名空间、类、类构造函数、类的成员等相关知识,在类的基本定义上就只缺少定义类的方法了,这是最简单的,使用function定义就OK了,如下就定义了一个getBooks的方法:
1//定义方法
2com.cnblogs.beniao.Book.prototype=
3{
4   getBooks : function()
5   {
6      return this._BookName+this._BookAuthor+this._BookPrice;
7   }

8}

      通过上面一系列的介绍,我们把所开发的代码整理下就完成了一个Books的类的定义,完整代码如下:
 1// JScript 文件
 2//-------------------JavaScript OO(Books)-------------------------//
 3//注册命名空间
 4Type.registerNamespace("com.cnblogs.beniao");
 5
 6//定义构造方法和成员
 7com.cnblogs.beniao.Books = function(name,author,price)
 8{
 9   this._BookName = name;
10   this._BookAuthor = author;
11   this._BookPrice = price;
12}

13
14//定义属性
15com.cnblogs.beniao.Books.prototype=
16{
17   get_BookName : function()
18   {
19      return this._BookName;
20   }
,
21   set_BookName : function(value)
22   {
23      this._BookName=value;
24   }
,
25   get_BookAuthor : function()
26   {
27      return this._BookAuthor;
28   }
,
29   set_BookAuthor : function(value)
30   {
31      this._BookAuthore=value;
32   }
,
33   get_BookPrice : function()
34   {
35      return this._BookPrice;
36   }
,
37   set_BookPrice : function(value)
38   {
39      this._BookPrice=value;
40   }
,
41   //定义方法,返回Books的信息
42   getBooks : function()
43   {
44      return this._BookName+this._BookAuthor+this._BookPrice;
45   }

46}

47
48//注册类
49com.cnblogs.beniao.Books.registerClass("com.cnblogs.beniao.Books");

三、抽象类与抽象方法
     通常说含有抽象方法的类即为抽象类,在面向对象的程序语言(如:C#,Java)里,定义有抽象方法的类必须定义为抽象类,那么JavaScript在面向对象的开发支持上的抽象类和抽象方法是怎么定义的呢,Microsoft AJAX Library对JavaScript的抽象方法有特别的定义----在Microsoft AJAX Library里在运行后直接抛出异常的类叫抽象类。也就是说,只要我们在定义的方法里直接throw出异常,那该方法所属的类就是一个抽象类了。可参考下买内定义:
抽象类与抽象方法

四、接口
      JavaScript也提供接口的定义,其定义和类的定义大致相同,使用registerInterface方法注册接口。从面向对象的知识来分析,接口里定义的方法我们可以称其为抽象方法,在上面的抽象方法的定义上已经介绍,定义一个抽象方法就是直接抛出异常,那是不是定义接口和接口方法也是直接抛出异常呢?答案是肯定的。如下就是一个完整的接口定义:
 1//注册命名空间
 2Type.registerNamespace("com.cnblogs.beniao");
 3
 4//定义一个接口
 5com.cnblogs.beniao.IBooks = function()
 6{
 7    throw Error.notImplemented();
 8}

 9
10//定义接口方法
11com.cnblogs.beniao.IBooks.prototype=
12{
13    getBooks : function()
14    {
15      throw Error.notImplemented();
16    }
,
17    getBooksCount :  function()
18    {
19       throw Error.notImplemented();
20    }

21}

      接口定义好后可以通过registerInterface方法注册接口,那么上面所定义的接口可以通过下面的方式来注册:
1//注册接口
2com.cnblogs.beniao.IBooks.registerInterface("com.cnblogs.beniao.IBooks");

      以上就完成了定义接口,定义接口方法以及注册接口的工作,但是还得注意很多知识点,JavaScript的接口是不能继承于其他接口的,由于JavaScript为弱类型语言,因此在Microsoft AJAX Library中的接口作用其实只是一种标记,你是不是完全实现了接口中的方法,它在运行期(定义时)是无法察觉是否完全实现了接口方法的,不像C#那样在编译时就要检测接口实现的完整性。

五、类、接口的继承及重写(抽象)方法
      1、类的继承和重写抽象方法
           在上面我们定义了一个抽象类Books,里面定义有一抽象方法getBooks(),那下面我们来看怎么去实现继承并重写这个抽象类的抽象方法;类的继承我们可以通过initializeBase方法来实现,调用父类的构造函数。语法格式如下:
1Namespace.Class = function()
2{
3    Namespace.Class.initializeBase(this,[param1,param2.]);
4}

5

     当父类没有构造函数的时候只需要使用父类里没有构造方法直接使用Namespace.Class.initializeBase(this);即可。比如现在有一个EnglishBook类,要去继承Books并重写getBooks抽象方法,则应该如下定义:
 1//=====================子类EnglishBook========================
 2com.cnblogs.beniao.EnglishBook = function(name)
 3{
 4   //调用基类的构造方法
 5   com.cnblogs.beniao.EnglishBook.initializeBase(this,[name]); 
 6}

 7
 8//重写基类抽象方法
 9com.cnblogs.beniao.EnglishBook.prototype=
10{
11   getBooks : function()
12   {
13      //..重写操作
14   }

15}

     通过继承除了重写父类方法外,我们还可以在子类里调用父类的方法,通过callBaseMethod方法来实现效用,如下:
 1//调用基类方法
 2com.cnblogs.beniao.EnglishBook.prototype=
 3{
 4   getBooks : function()
 5   {
 6      //this:代表当前对象
 7      //"getBooks":代表父类里的方法
 8      com.cnblogs.beniao.EnglishBook.callBaseMethod(this,"getBooks");
 9   }

10}
      callBaseMethod方法有两个参数,this代表当前对象,第二个参数代表要调用父类里的哪一个方法名。这时还有一个必须的不成才能完成继承关系的建立,那就是在注册子类的时候给它提供父类。注册完毕,就算是大功告成。
1//com.cnblogs.beniao.EnglishBook--子类
2//com.cnblogs.beniao.Books--------子类实现的父类
3com.cnblogs.beniao.Books.registerClass("com.cnblogs.beniao.EnglishBook",
4                                       "com.cnblogs.beniao.Books");

     2 、接口的实现和方法重写
          关于JavaScript面向对象的支持基本上介绍得差不多了。剩下这最后一个知识点,那好,下面我们就来讨论下接口的实现和方法重写的相关知识。在本问上面介绍接口的时候已经定义好了一个接口IBooks,并定义了两个抽象方法getBooksgetBooksCount,那么我们应该怎么去实现一个接口并实现接口方法呢?下面以实现getBooks方法来介绍下接口的继承实现,参考下面代码实现:

 1com.cnblogs.beniao.EnglishBook = function(name)
 2{
 3   this._BookName = name?name:"English";
 4}

 5
 6//实现接口方法
 7com.cnblogs.beniao.EnglishBook.prototype=
 8{
 9   getBooks : function()
10   {
11      return "This is English books!";
12   }

13}

      关键的就是这最后一步了,我们这时需要注册Englishgbook这个类,同样使用registerClass方法,而与上面实现类继承上有点小小的差别,那就是在注册是时候给实现类提供接口,详细如下:
1//注册类的时候并提供所实现的接口
2//第二个参数为所继承的类,当没有父类的时候使用null
3com.cnblogs.beniao.EnglishBook.registerClass("com.cnblogs.beniao.EnglishBook"null,
4    com.cnblogs.beniao.IBooks);
接口示例的完整代码

      一个类是支持实现多个接口的,实现方式是在注册类的时候把把所实现的多个接口都提供给registerClass方法。

     关于JavaScript在Microsoft AJAX Library的支持下的面向对象开发基础,大致也就上面所介绍的这些,本文就简单的介绍于此,更多的知识有兴趣的朋友请查阅相关书籍或资料。

-----------------------------------------------------------------------------------------------------------

原文地址:https://www.cnblogs.com/beniao/p/1204388.html