您的位置:首页 > Web前端 > JavaScript

JavaScript继承机制模拟实现

2004-09-07 13:22 686 查看
.Afr_ARTICLE_TITLE
{
font: NORMAL BOLD 14px "Tahoma";
}
.Afr_CONTENTS
{
font: NORMAL NORMAL 12px "Tahoma";
line-height: 22px;
}
.Afr_CODE
{
font: NORMAL NORMAL 11px "Courier New";
line-height: 20px;
width: 100%;
background-color: #EEEEEE;
padding: 5 10 5 10;
}
.Afr_COMMON
{
color: #55BB55;
}
.Afr_STRING
{
color: #EE0000;
}

最近因为学校做网站设计,所以一直在ASP上和数据库上大费苦心。我在前一个阶段是做Java程序设计的。突然接到任务并学习ASP,所以我一直都热忠并善于利用JavaScript来构架ASP程序。 JavaScript的一个明显的优点就在于它可以定义和持有自己的对象。这一点好象是VBScript所无法比拟的。有了这一点,可以利用JavaScript进行更接近于面向对象的程序设计。也许这将使网站开发更有乐趣...
但有个严重的缺点!JavaScript不支持继承机制。不象Java那样,支持extends关键字(虽然这个关键字在JavaScript中是保留字)。在微软的ASP.NET中,JavaScript才开始提供比较完善的对继承机制的支持。 PHP语言当然也有继承机制的支持,这些都叫我垂青... 不过现在我根本无法说服学校的老头子们买更好的域名空间,但是我也不想忍受ASP中无继承机制之苦,所以急中生智,也就有了一些成果! JavaScript根本不支持继承机制!这是可以肯定的。但是我们可以想办法做些手脚,模拟一个出来。
废话说了一堆,先来看一个例子:
function Person()
{
public:  // 注意这个public!
this.GetName=Person_mfGetName;
private: // 注意这个private!
this.m_strName="Guest";
}
function Person_mfGetName()
{
return this.m_strName;
}
var MyPerson=new Person();
MyPerson.GetName();

注意上面的程序中的两个关键字:private 和 public。其实没有这样的用法,这只是我的习惯。 幸好在实际应用中不会有错。
你可以用任何输出语句来查看结果。当然结果一目了然,会在浏览器窗口中出现:Guest 字样。这是第一步!下面是关键一步:继承!
function Student() // Extends Class: Person
{
EXTENDS:   // 注意这个EXTENDS不能使用小写字母形式
this.Super=Person; // 定义指向其"父类构造器"。Super也不能用小写形式
this.Super();  // 调用其"父类构造器"
private:
this.m_nStudentID=0;
}

使用EXTENDS这也是我的习惯,但要切记一定不能使用小写字母。因为extends是JavaScript中的保留字。
而随后定义和调用“父类构造器”就可以从“父类”那里“继承”所有的属性和方法。虽然在Student中并没有看到GetName()方法,但是却可以调用。因为他已经继承了Person的GetName()方法。
var MyStudent=new Student();
MyStudent.GetName(); // 调用"父类"的GetName(),结果为返回 "Guest"

关于JavaScript继承实现就是这样。只要牢记两步:

在“子类”中先定义一个指向“父类构造器”的函数(什么名字都可以,我习惯使用Super)
随后调用这个函数

这样就可以继承“父类”的所有属性和方法!
这种“继承机制”的原理是十分简单的。它的原理有点类似于C/C++语言中的include关键字的用法。当一个C/C++源程序在被编译的时候,编译器会将include字段直接替换成其所指文件的全部内容。而我所采用的JavaScript继承原理也是如此。先将一个“类”的成员函数指向“父类构造器”,在随后的函数调用中,自然就会把“父类”中的所有成员“添加”到该“类”中。
我现在有些怀疑的是,既然extends和super都是保留字,那为什么JavaScript却不支持继承呢?不知道有没有其他更好的办法?希望各位指点...

继续关于JavaScript继承机制的讨论。
不过,在继续讨论之前我们先来看一个实例:
function Shape()
{
public:
this.CalcuArea=Shape_mfCalcuArea; // 计算面积
}
function Shape_mfCalcuArea()
{
// ...
}

很明显的,这个Shape类下的CalcuArea()方法应该是个抽象函数。在Java中可以使用abstract关键字定义抽象函数,而在JavaScript中也没能支持这个特性。抽象函数不应该具有函数体,或者换句话说:在调用Shape.CalcuArea()时应该报错,并终止ASP脚本程序。从PHP程序设计中吸取一些设计经验,我们可以这样处理:
function Shape_mfCalcuArea()
{
Response.Write("Error, Method Shape_mfCalcuArea Is Abstract");
Response.End();
}

这样做,就可以“迫使”自己在Shape的继承类中编写代码重载CalcuArea()方法。
你也可以直接让Shape类下的CalcuArea函数等于null,让服务器指出运行中的错误。
在Shape的继承类Rect中,我们可以通过改变CalcuArea变量所指向的函数,来模拟实现CalcuArea方法的重载。
function Rect()
{
EXTENDS:
this.Super=Shape;
this.Super();
OVERRIDE:
this.CalcuArea=Rect_mfCalcuArea;
}
function Rect_mfCalcuArea()
{
// ...
}

如果一个类中含有抽象函数,那么这个类必定是抽象类!抽象类是不能被实例化的,必须被子类继承。遗憾的是JavaScript也不支持抽象类定义(如果JavaScript真的支持“抽象类”机制,那么必定支持“继承”机制)。
如何实现抽象类机制,我想其大概思路应该和上面的抽象方法类似。还是利用 Response.End() 强制结束程序,并在这之前告之程序员:“该类是一个抽象类”。但不同的是这个方法要用在类的“构造器”中。这样就可以使一个抽象类不能被实例化。
JavaScript比较特殊,把类定义和构造器捆到一起。那么这样的形式是不是对的呢?
function Shape()
{
Response.Write("Error, Class Shape Is Abstract");
Response.End();
// 其它代码 ...
}
var MyShape=new Shape(); // 会被告之出错 OK
function Rect()
{
EXTENDS:
this.Super=Shape;
this.Super();
}
var MyRect=new Rect(); // 仍会被告之出错 OH, NO

因为Shape是一个抽象类,所以在声明第一个MyShape对象时出现了警告。这是我们所期望的。而Rect类很好的继承了Shape类,但还是被告之“Error, Class Shape Is Abstract”。
这是我的关于JavaScript继承实现思想所留下的遗憾。必须再“变通”一下才能“完美”的实现抽象类。我还是采用了一种比较愚笨的精明方法。
说其“愚笨”,是因为这种方法通过判断变量值实现的。而又说其“精明”,是因为这个方法采用了最少的变量。
function Shape()
{
if(!this.Super)
{
Response.Write("Error, Class Shape Is Abstract");
Response.End();
}
// 其它代码 ...
}
var MyShape=new Shape(); // 会被告之出错 OK
function Rect()
{
EXTENDS:
this.Super=Shape;
this.Super();
}
var MyRect=new Rect(); // 顺利继承 YES, OK

在调用Shape构造器时,Shape类中根本就没定义this.Super成员变量,所以肯定要警告错误信息。而在Rect类中,首先就定义了this.Super的去向:就是指向Shape的构造器。所以在随后的函数调用中,Shape类构造器不会认为this.Super为空了,也就放行让我们通过了...
这个抽象类的实现思想还可以继续获得延伸。比如一个抽象类的子类还是抽象类,那么你可以在这个子类构造器的最开始部分加入上面的判断代码。
通过这些示例,我想你可以从中扩充更广的面向对象的特性。篇幅有限,至此收笔。
如果你有好的提议,请与我联系:Afritxia2003@yahoo.com.cnafritxia@hotmail.com
在文章结束的时候,我给出了一个运行于客户端的JavaScript脚本程序,可以通过查看页面源码来浏览。
这段代码演示了我上面所说的内容,绝不含有任何恶意程序。

//
// 演示程序
function MSG() // MSG 抽象类定义
{
ABSTRACT_CLASS:
if(!this.Super)
{
document.write("Class MSG Is Abstract
");
// Response.Write(...);
// Response.End();
}
public:
this.Show=MSG_mfShow; // this.Show=null;
private:
this.m_nMainID=0;
}
function MSG_mfShow()
{
}
function MSGCard() // MSGCard 抽象类定义, 继承自 MSG
{
ABSTRACT_CLASS:
if(!this.Super)
{
document.write("Class MSGCard Is Abstract
");
// Response.Write(...);
// Response.End();
}
EXTENDS:
this.Super=MSG;
this.Super();
}
function BBSMainCard()
{
EXTENDS:
this.Super=MSGCard;
this.Super();
OVERRIDE:
this.Show=BBSMC_Show;
}
function BBSMC_Show()
{
document.write("BBSMainCard.Show()");
document.write("BBSMainCard.m_nMainID="+this.m_nMainID);
}
var MyMSG=new MSG();
var MyMSGCard=new MSGCard();
var MyMainCard=new BBSMainCard();
MyMainCard.Show();

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: