这是dojo.declare中的三个极度蛋疼的功能,在对多继承的实质有所了解之后,才会加深对这三个功能的认识,所以放到最后说。这里就不谈它们的实现原理了,第四章中也许会描述到= =!
如果觉得运行constructor前后缺少了些什么,那么preamble、postscript可以很好的帮助我们进行弥补。根据我时间不长的开发经验,还想不出什么情况下需要这种操作来弥补。如果在类型的定义中包含了preamble方法,那么在这个类型的构造函数被调用之前,会首先执行一次preamble。同样如果定义了postscript方法,那么该类型的构造函数被调用之后,也会自动执行一遍postscript。下面是一个简单的例子:
dojo.declare('A',null,{
preamble:function(){ console.log('A'); },
constructor:function(){ console.log('AA'); },
postscript:function(){ console.log('AAA'); }
});
var a= new A();
/*输出:
A
AA
AAA
*/
至于preamble和postscript方法究竟是如何被调用的,第四章中有解释,暂时不需要关注,可以认为这是Dojo提供好的机制。来个复杂一些的例子:
dojo.declare('A',null,{
preamble:function(){ console.log('A'); },
constructor:function(){ console.log('AA'); },
postscript:function(){ console.log('AAA'); }
});
dojo.declare('B',A,{
preamble:function(){ console.log('B'); },
constructor:function(){ console.log('BB'); },
postscript:function(){ console.log('BBB'); }
});
dojo.declare('C',B,{
preamble:function(){ console.log('C'); },
constructor:function(){ console.log('CC'); },
postscript:function(){ console.log('CCC'); }
});
var c= new C();
/* 输出:
C
B
A
AA
BB
CC
CCC
*/
从输出的结果来看,我们可以挖掘出一些有意思的事情。在这种拥有继承的情况下,父类中postscript方法是不会被自动调用到的。上述例子的准确函数执行顺序是:
写道
1. C.preamble
2. B.preamble
3. A.preamble
4. A.constructor
5. B.constructor
6. C.constructor
7. C.postscript
至于为什么不会调用到A和B的postscript方法,从Dojo的源码实现上讲是因为这里所调用的父类型的constructor并没有去执行postscript方法。换个角度说,这里调用父类型的constructor函数完成的构造过程,与我们直接通过new来调用的父类型发生的构造,是两回事。归纳来说,对类型L(A)= AA1A2A3…AN使用new进行实例化时,默认的执行顺序是:
写道
A.preamble-> A1.preamble-> A2.preamble ... AN.preamble->
AN.constructor-> AN-1.constructor ... A.constructor->
A.postscript
在Dojo1.4之后的版本中,preamble已经被标记为deprecated函数,不过postscript并没有被列入deprecated。chain提供了自动执行父类中函数的功能。默认情况下,只有父类的构造函数是会被自动调用的,并且总是先于子类的构造函数执行。只有在一些特殊情况下,我们会需要让其他的函数也能够像构造函数一样,自动执行,免去我们手工调用的麻烦。举例来说,如果创建的类型包含了destroy函数,该函数会进行一些垃圾回收方面的工作,我们肯定希望destroy函数完成后也会自动去执行一下父类中的destroy。
下面的例子定义了一条destroy函数组成的chain。其中的允许我们来设置函数的执行顺序,这里指定的是before顺序,也就是说子类的函数会先于父类的函数执行,所以子类的destroy先运行。
dojo.declare('A',null,{
constructor:function(){ console.log('A'); },
destroy:function(){console.log('AA');}
});
dojo.declare('B',A,{
constructor:function(){ console.log('B'); },
destroy:function(){console.log('BB');}
});
dojo.declare('C',B,{
"-chains-": {
destroy: "before"
},
constructor:function(){ console.log('C'); },
destroy:function(){console.log('CC');}
});
var c= new C();
c.destroy();
/*输出:
A
B
C
CC
BB
AA
*/
有两点值得注意:
第一点是"-chains-"语句所处的位置,上例中放在了C类型的定义中。如果放在A或者B类中,执行c.destroy()的效果还是一样的。事实上,只要把chain声明放在继承链条中的任何一个类型定义里,都可以达到串连所有同名函数的效果。对于复杂的多重继承结构也是这样的,因为他们实质上最终还是一条单继承结构。
第二点是chain中允许我们声明三种类型的顺序,他们能够产生效果的对象不同。字面上,我们能够使用的是after\before\manual这三个顺序,他们分别代表了在父类函数执行之后执行、在父类函数执行之前执行、手动调用。对于非构造函数,设置manual是没有意义的,如果不是after顺序,会被一概视为before。而对于构造函数,设置before是没有意义的,因为父类的构造函数要么manual手动调用,要么一定会在子类的构造函数之前执行。
dojo.declare('A',null,{
"-chains-": {
constructor: "before", //没有作用,非‘manual’即被视为‘after’
foo: "manual" //没有作用,非‘after’即被视为‘before’
},
constructor:function(){ console.log('A'); },
foo:function(){console.log('AA');}
});
dojo.declare('B',A,{
constructor:function(){ console.log('B'); },
foo:function(){console.log('BB');}
});
dojo.declare('C',B,{
constructor:function(){ console.log('C'); },
foo:function(){console.log('CC');}
});
var c= new C();
c.destroy();
/*输出:
A
B
C
CC
BB
AA
*/
最后来看一个针对构造函数设置manual的例子。
dojo.declare('A',null,{
"-chains-": { constructor: "manual" },
constructor:function(){ console.log('A'); }
});
dojo.declare('B',A,{
constructor:function(){ console.log('B'); }
});
dojo.declare('C',B,{
constructor:function(){
this.inherited(arguments); //设置为manual后,只能手动调用父类函数
console.log('C');
}
});
var c= new C();
/*输出:
B
C
*/
从这个例子可以看出,在设置了manual后,如果不手动去调用父类的构造函数,那么父类的构造函数是不会执行的,因此这里就不会打印A,根据第二章中的描述,手动调用可以使用inherited方法。
PS,之前我以为preamble、postscript以及chain会在dijit中被较多使用到,但根据在Dojo1.5源码中的搜索,很不幸,只有postscript在dijit中被使用过,至于preamble和chain基本上在整个Dojo的实现代码中都没有,只有在test的代码里出现过两三次。可见这些功能偏门
到什么程度。我觉得API提供的原则应该是简单易用
,而Dojo的接口往往体现着庞大复杂精深,我想这可能也是很多web fronter不愿意花成本去学习去使用的Dojo的原因吧。其实作为开发者来说,Dojo用熟了也并没有感觉太复杂,你甚至会为它的细致周全感到震撼,但是对于初学者来说,或者是那些急于上手某个Ajax框架进行开发的人,Dojo的确不是一个好的选择。
分享到:
相关推荐
dojo_part001_001_001dojo_part001_001_001dojo_part001_001_001
dojo_part003_003_003dojo_part003_003_003dojo_part003_003_003
《Dojo-China.zip》是关于Dojo工具包的实战指南,源自chinadojo1688,主要针对中文用户,提供了丰富的Dojo编程知识。Dojo是一个强大的JavaScript库,尤其在构建富互联网应用(RIA)时,其功能和性能表现卓越。这个...
JavaScript使用原型链实现面向对象编程中的继承机制。 - **prototype**: 每个函数都有一个 `prototype` 属性,用于指定实例化对象的默认属性和方法。 - **__proto__**: 每个对象都有一个 `__proto__` 属性,指向它...
【Dojo.GUI_v6.zip for pencil】是一款专为Pencil设计的GUI模板资源包,它扩展了Pencil这款优秀的Web原型设计工具的功能和视觉元素。Pencil是一个免费且开源的应用程序,允许用户创建各种交互式原型,适用于网页、...
Dojo API中文参考手册是一个面向初学者的指导性文件,它详细介绍了Dojo框架的体系结构、常用包及功能,并通过附加注释实例帮助开发者理解和使用Dojo。以下是根据给定内容整理的知识点: 1. Dojo体系架构分层: - ...
1、把 ini.js与dojo.js中的 HOSTNAME_AND_PATH_TO_JSAPI 改成 baseUrl:"http://localhost/hrp_gis/common_railway/arcgis_js_api/library/4.11/dojo" 2、引用 arcgis_js_api 3、跨域 : 1、停掉ArcGIS Server的...
dojo学习001_20101122.dojo学习文件
3. **dojo/ready**:这个模块用于确保DOM加载完成后再执行指定的函数,它是Dojo中的一个实用工具,常用于页面初始化。 4. **dojo/store**:这是一个数据存储抽象层,提供了一种统一的方式来访问和操作数据,无论...
例如,Dojo Mobile中的Container Widget就是一种管理其他部件如何在不同屏幕尺寸和方向下显示的工具,它能够帮助开发者处理视区变化导致的布局问题。 总之,随着智能手机和移动设备的普及,为这些设备开发Native-...
7. 事件处理:Dojo的事件API支持面向切面编程(AOP),以及主题和事件队列的功能,这为开发者提供了更多的事件处理灵活性。 Dojo的设置和配置是应用开发中的重要步骤,包括选择正确的Dojo版本、动态加载package以及...
3. **DOM操作 (dojo/dom, dojo/dom-geometry, dojo/dom-style)**: 这些模块提供了对DOM元素的广泛操作,包括查找、创建、修改和布局计算。`dojo/dom`用于获取和操作DOM元素,`dojo/dom-geometry`处理元素的几何属性...
在开发Web 2.0应用程序时,Dojo作为一个强大的JavaScript库,提供了丰富的功能和组件,帮助开发者构建交互式和高性能的网页应用。然而,随着应用复杂性的增加,性能优化成为了一个不可忽视的话题。本文将深入探讨...
《dojo中文文档-dojo手册》提供了全面而深入的Dojo框架知识,这是一份非常有价值的资源,对于想要理解和掌握Dojo JavaScript库的开发者来说至关重要。Dojo是一个强大的JavaScript工具包,它提供了丰富的功能,包括...
coding_dojo_mern_stack:编码Dojo Mern堆栈