分享
 
 
 

深入探索Javascript对象机制

王朝html/css/js·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

1) Javascript 继承机制的不足和改进

问题(1)由于javascript是采取prototype机制的“伪继承”,prototype必须显示引用“基类”对象,所以注定了javascript只能实现“弱继承”,或者叫做“对象继承”

注意这里的次序关系需要很明确,prototype的赋值必须在对象构造之外。

例如:

function classA()

{

classA.prototype.methodA = function() {...}

}

function classB()

{

classB.prototype.methodA = function(){...}

}classB.prototype = new classA();

//注意这里声明B继承自A出现在function classB()函数体之外,并且先于

//classB对象的构造被执行。

由于是这样一种机制,所以有两点需要注意:第一,在类的构造函数中不应当执行任何持久化操作,如全局的或者dom对象的构造,因为如果你这么做了,当使用这个类作继承的时候,即使你只实例化一个对象,这个类的构造函数也可能被执行超过一次!(相反地,在真正面向对象的语言,如C++和Java中,当我们采用Singleton模式的时候,常常被允许在构造函数中执行持久化操作,如果习惯了这种模式,在javascript中很容易出错!)

例如:

function uniqueForm(url)

{

this.id = 'myform';

this.action = url

uniqueForm.prototype.Form_Submit = function(){...}

this.form = document.creatElement('form');

//问题出在这里,在构造函数中进行了持久化操作

......

}

function uniqueValidateForm(url)

{

......

......

}uniqueValidateForm.prototype = new uniqueForm();

var myForm = new uniqueValidateForm('test.aspx');

//这个语句被执行的时候其实已经构造的是第二个form元素了,

//第一个元素在继承语句uniqueValidateForm.prototype = new uniqueForm();

//中已经被构造出来了。

一个避免这个问题的方法是采用工厂:

function formFactory()

{

formFactory.getCurrentForm = function()

{

if(formFactory.form == null)

{

formFactory.form = document.createElement('form');

}

return formFactory;

}

}

把上面例子中两个类的document.createElement('form');改成formFactory.getCurrentForm()即可。

问题(2)类属性的继承:问题的根源同样在于javascript的对象继承机制。通过prototype实现的继承很容易获得基类的对象属性和对象方法,但是却根本不可能获得基类的类方法。而真正的面向对象继承,应当是同时继承类和对象方法才行。一种基本上可以解决这个问题的方案是使用反射遍历基类的方法加到子类方法中去。例如:

function classA()

{

classA.prototype.methodA = function() {...} //这是一个对象方法

classA.methodA = function(){...} //这是一个类方法

}

function classB()

{

......

}classB.prototype = new classA();

for (each in classA)

{

classB[each] = function(){classA[each]}; //将classA的类方法也继承下来

}

var obj = new classB();

obj.methodA(); //调用继承自A的对象方法

classB.methodA(); //调用继承自A的类方法

问题(3)带参数的基类构造:正如上面提到的,由于prototype和对象继承的限制,在构造派生类对象之前必须先实例化基类对象,这给我们实现带参继承带来了很大的麻烦。一种解决方法是等到需要构造对象的时候才去处理继承

例如:

classB.prototype = new classA(1, 2); //在一次构造之前才实现继承

var objB = new classB(1, 2);

classB.prototype = new classA(-1, -2);

//另一次构造,参数不同所以要重写继承

var objC = new classB(-1, -2);

当然,像上面这样的做法给人的感觉很不好,都有点不像是继承了。

还有另外一种做法是令B的构造函数不依赖于A的构造函数,也就是说在B中重写所有A中实现的构造函数逻辑,而仅仅继承B的属性域和方法域,这样在声明继承的时候只要提供给A的构造函数任意一组合法的参数就行了。当然这种方法也很麻烦。

事实上要解决上面这个问题,必须考虑在B中保留对A域的访问并且将构造函数逻辑抽象出来。

例如:

function classA(x, y)

{

classA.prototype.constructor = function(x, y)

{

......

}

......

if (x != null || y!=null) this.constructor(x, y);

}

function classB(x, y)

{

classB.prototype.constructor = function(x, y)

{

this.base.constructor(x, y); //先调用基类的构造函数

...... //再执行自己的构造函数

}

......

if (x != null || y!=null) this.constructor(x, y);

}classB.prototype = new classA();classB.prototype.base = new classA();//用无参继承

var objB = new classB(1, 2);

var objC = new classB(-1, -2);

2)事件驱动机制和回调函数实现

javascript的灵活性使得其实现事件驱动和回调是很方便的,唯一的困扰就在于this指针。一般来说,在面向对象中我们希望对象方法的this指针仅仅指代对象本身,而不应当有其他含义。在一般情况下,this指针在javascript的对象方法中也能很好的工作,但是很可惜在面对回调和事件驱动的时候就不适用了。根本原因是因为javascript的this指针是随着调用者而改变的。在一般的对象方法中,调用者自然是对象本身,然而在回调函数和事件函数中,调用者可能是外部对象或者事件的真正传播者。

例如:

function classA()

{

this.button = document.createElement('input');

this.button.type = 'button';

......

......

this.button.onclick = classA.prototype.Button_Click;

this.text = '请点击';

this.count = 0;

......

......

......

classA.prototype.Button_Click = function() //这样写得不到正确的结果

{

alert('点击次数:" + ++this.count); //因为此时的this已经代表调用者

this.button.text = '请再次点击'; //button,而不是classA对象了

}

}

在复杂的事件和回调中,可能还会包含成员函数之间的相互调用和事件的关联,我们当然不能将大量的精力花费在判断this指针所属上,一种比较巧妙的解决方法是引入一种固定的事件注册模式,如上面的代码写成:

function classA()

{

this.button = document.createElement('input');

this.button.type = 'button';

......

......

this.button.eventHandler = this;

this.button.onclick = function(){this.eventHandler.Button_Click(this, event);}; //注意这个函数内的this实际上在执行的时候代表button

this.text = '请点击';

this.count = 0;

......

......

......

classA.prototype.Button_Click = function(sender, event) {

alert('点击次数:" + ++this.count); //正确了

this.button.text = '请再次点击'; //或者sender.text更为简单

}

}

3)抽象类(abstract Classes)

抽象类是面向对象设计中的一种重要元素,要发挥javascript面向对象的多态力量,必须要寻找一种实现抽象类的机制。

Javascript的灵活性使得我们可以用一种简单的方式实现它

例如:

function abstractA(Implemented)

{

abscractA.prototype.A = function(){...}

......

......

......

if (Implemented != true)

{

throw new Error('抽象类abstractA不能构造实例!');

}

}

function classA()

{

......

}classA.prototype = new abstractA(true);

4)接口:接口也是一种非常重要的元素,然而实现它比较复杂

下面是一个例子:

function InterfaceA(objA)

{

if (objA.methodA == objA.methodA)

throw new Error('InterfaceA的方法MethodA在对象中未实现!");

if (objA.methodA == objA.methodB)

throw new Error('InterfaceA的方法MethodB在对象中未实现!");

......

......

}

function classA()

{

......

}classA.prototype = new InterfaceA(new classA());

5)高级反射技术——元数据管理和多态回调

我们利用javascript类生成了一个对象之后,如何能够在外部快速地获得这个对象的句柄,反射技术为我们提供了一个思路,甚至我们还能在运行时环境中动态地获得一个类家族的所有实例而不需要事先知道它们的对象名。另外,这种技术的一个重要用途是实现局部对象的持久化。

由于这是一个比较复杂的应用,只有在一些复杂的任务中才能体会到它的便利,这里只能举一个极其简单的例子:

function classA(id)

{

this.id = id; //这个ID对于元数据的建立是重要的

classA.instances[id] = this;

classA.instances.All.push(this);

......

......

}

classA.instances = new Array();

classA.instances.All = new Array();

var objA = new classA('myObjA');

在外部用classA.instances['myObjA']可以直接访问objA而无需知道对象名objA,另外还可以通过对classA.instances.All遍历来访问所有classA的实例。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有