在JavaScript面向对象编程中使用重载

本文详细介绍了JavaScript面向对象编程中继承的概念,并解释了如何在继承中实现重载。通过实例展示了重载技术在解决类间方法调用冲突时的应用,以及在实现特定功能时的局限性。最后,给出了一个基于'附加继承法'的ListView控件实例,展示了此技术的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在此之前,我写了一个'在javascript面向对象编程中使用继承'的一系列文章。有很多的热心网友参与了讨论,指出了其中很多的问题并给予了我很多的好建议,非常感谢他们。同时在oop中和继承关系非常紧密的就是重载这个东西,那么我介绍的继承方法支持重载吗?

这里我要说的重载(override),确实就是传统oo中的重载,而不是我们在javascript对象中对其同名属性或方法的重写(rewrite)。在此我就不详细讲什么是oop中的override了,因为只要是使用.net来编程的程序员都应该很了解的。

在我们的附加继承法的核心代码中:

for ( var key in base )

{

if ( !this[key] )

{

this[key] = base[key];

if ( typeof(base[key]) != 'function' )

{

delete base[key];

}

}

}

this.base = base;

delete base[key]的作用是删除掉基类对象实例中的属性,因为它们都已经被shallow copy到子类实例中了。而this.base = base;的作用是保留了基类对象实例,实际上就是保留了基类中的所有方法,这些保留下来的方法同时也是shallow copy到子类中了的。只是我们在子类中可以方便的将其rewrite,注意这里不是override,而一定是rewrite。rewrite后其实子类实例中就没有了基类中copy过来的同名方法了。

不过由于我们保留了对基类实例的引用this.base = base;,所以即使在子类中被rewrite的方法,基类中仍然可以使用this.base.methodname()来访问。这个调用基类方法的语句已经和c#中的override后调用基类方法非常的相似了,我们就这么来调用基类方法可以吗?当然是不可以的,因为这时的方法都属于基类对象base,它是无法访问子类中的属性的。不过幸好jscript提供两个函数,call和apply,于是我们可以使用这样两个方法来重新应用this(子类实例)对象。调用语句如下:

this.base.methodname.call(this);

this.base.methodname.apply(this, arguments);

第一个语句用来处理没有参数的override的情况,第二个用来处理调用子类方法有参数,而其参数还需要原样传入基类方法的情况。这样的override语句虽然算不时上sexy,不过他的好处是对基类方法的编写没有任何的要求,而且即使错误的使用了this.base.methodname()还是比较容易debug出错误来的。

这个override最大问题是什么呢?就是它只能支持对子类中,没有使用同样override方法的方法进行这种override。好绕口,看看下面这个实例就知道问题了:

html>

head>

title>researh override in javascript ooptitle>

meta name="author" content="birdshome@博客园" />

head>

body>

script language="javascript">

function grandpa(name, familyname)

{

this.name = name;

this.familyname = familyname;

}

grandpa.prototype.getname = function()

{

return "grandpa's name: " + this.name;

};

grandpa.prototype.getfamilyname = function()

{

return "grandpa's family name: " + this.familyname;

};

function father(name, familyname)

{

this.extends(grandpa);

this.name = name;

this.familyname = familyname;

}

father.prototype.getname = function()

{

return this.base.getname.call(this) + "\r\nfather's name: " + this.name;

};

function son(name, familyname)

{

this.extends(father);

this.familyname = familyname;

this.name;

}

son.prototype.getname = function()

{

return this.base.getname.call(this) + "\r\nson's name: " + this.name;

};

son.prototype.getfamilyname = function()

{

return this.base.getfamilyname.call(this) + "\r\nson's family name: " + this.familyname;

};

script>

script language="javascript">

var g = new grandpa('michael', 'william');

alert(g.getname());

var f = new father('john', 'william');

alert(f.getname());

var s = new son('tom', 'william');

// alert(s.getname());

alert(s.getfamilyname());

script>

body>

html>

// 运行示例代码需要'附加继承法'中那个extends方法的支持

三个类grandpa、father和son,它们分别具有两个属性和两个方法。其中的getname方法,是从father中调用了grandpa中被override的同名方法,然后又从son中的getname调用了father中被override的同名方法。这样就在执行son中的getname时,在father中的getname方法中产生死循环,最后stack overflow,ie crash。而其中的getfamilyname方法,是从son中调用grandpa中被override的同名方法,而grandpa中的getfamilyname没有再调用任何override方法,所以可以正确的运行。

由于javascript的oop始终是在做一些模拟的工作,除了能实现某些模拟出来的功能外,同时实现模拟的代码的复杂度也是应该考虑的,像这样的override从代码实现上看非常的轻量级,而且也是很容易理解的。同时可以满足绝大多数的js控件的开发,随后我会再给出一个listview控件的事例,它的实现完全基于'附加继承法'和我这篇文章中所讲到的'重载'技术。

非常欢迎您的宝贵意见和建议,让我们开发的更好(copy了dudu的语录:)。

attention:运行代码alert(s.getname())一定要关闭其它的ie,或避免正在任何ie中填写表单。

绿色通道:好文要顶关注我收藏该文与我联系


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值