dojo.declare,dojo.define,dojo.require解释

转载自http://blog.chinaunix.net/uid-27024249-id-4023752.html

dojo.declare在dojo中被广泛使用,理解它将对弄懂dojo的代码有很大帮助。简单的说,dojo.declare提供了一种声明类的方式,通过它可以很方便的扩展其他类:

dojo.declare("com.abc.MyDataProvider"/*类名/,dojo.widget.ComboBoxDataProvider基类

  • {object,start/

  • name:"My DataProvider":function(){

  • ..

  • }

  • }/

  • )

  • 这里类名com.abc.MyDataProvider是用字符串来表示的,dojo.widget.ComboBoxDataProvider是被扩展的基类,第三个参数是个object,用来定义该类的属性。 dojo.declare产生的类所具有的属性将是基类的属性和大括号中指定的属性的集合,如果大括号中声明了和基类同名的属性,则基类属性将被覆盖,但也有例外,下面将会说明。生成类的constructor将会调用基类的constructor,然后调用本身的initializer方法,该方法可以来自类本身,也可以来自其基类,如果都没有还可以来自dojo.declare中可选的一个参数,否则将是个空函数。

    如何使用产生的类呢?可以把该名字作为function类型的变量名来使用,如

    1. dp=new com.abc.MyDataProvider)

    可见dojo.declare产生了一个指定名称的变量,引用创建出的class(function) 也可以:

    1. dpClass=dojo.evalObjPath"com.abc.MyDataProvider");

    2. dp=new dpClass)

    这种方式比较适合通过类名字符串来使用该类。
    1. 覆盖的问题
    如果基类是这么声明的:


    1. .ComboxDataProvdier=function{

    2. this.init{

    3. .

    4. }

    5. }

    而我们希望com.abc.MyDataProvider里声明的init方法覆盖基类的方法,那么上面那个dojo.declare的结果是不对的,这时查看该类的一个实例,你会发现它的init属性是基类的方法。

    dojo.declare先会把dojo.widget.ComboBoxDataProvider.prototype上的属性设置到 com.abc.MyDataProvider.prototype上,然后再把本身声明的属性加进去,因此 com.abc.MyDataProvider.prototype的init属性正是我们期望的init函数,但是当执行该类的constructor 方法时,它会调用基类的constructor,因此本来设置好的init函数就被基类的init函数覆盖了,于是override失败。

    这里的ComboDataProvider作为一个class,不应该在constructor里赋值init属性,这样会导致每个实例都会有一个init方法的实例,而这是没有必要的。应该用prototype来定义method属性:
    com.abc.MyDataProvider.prototype.init = function() {
    ...
    }
    由此可见,用dojo.declare来override还是有个前提的,那就是要override的method必须用prototype定义,而不是在constructor里。
    2. 多重继承

    dojo.declare是可以扩展多个类的,如: dojo.declare("dojo.widget.html.ComboBox",dojo.widget.HtmlWidget,

    { ... }

    ); 这时第一个类dojo.widget.HtmlWidget将会被作为super class,于是其prototype上的属性将会进入dojo.widget.html.ComboBox.prototype,然后其他基类 prototype上的属性也会被mixin到dojo.widget.html.ComboBox.prototype,最后是类本身声明的属性。当然 在constructor只会调用基类的construtor。

    这有点类似java的单根继承、多个接口,不过要注意的是:如果dojo.widget.HtmlWidget和 dojo.widget.ComboBox同时声明了一个函数属性,那么产生的类将会具有dojo.widget.ComboBox里声明的函数,这时如 果dojo.widget.ComboBox因为是一个接口类而把该属性声明为空函数,而你希望继承的是dojo.widget.HtmlWidget上 该方法的实现,那么结果就不对了,你得到的类的该方法将是dojo.widget.ComboBox上的声明的空函数。

    Dojo 学习(1):简单方法的定义和使用

    可参考官方教程:http://dojotoolkit.org/documentation/tutorials/1.7/hello_dojo/
    教程里主要定义了两个方法,setText设置文本内容和restoreText重置文本内容。
    这两个方法通过dojo.define这个方法来定义。

    1. // demo/myModule.js

    2. IndemomyModule.js(which means this code defines the"demo/myModule"module):


    3. define

    4. //The dojo/dom moduleisrequired by this moduleinthis list of dependencies["dojo/dom"](dom{


    5. /Once all modulesinthe dependency list have loadediscalledtodefine the demo/myModule module/

    6. ispassed as the first argumenttothis;additional modules

    7. // inthe dependency list would bepassedinas subsequent arguments.


    8. var oldText{};


    9. /This returned object becomes the defined value of this module

    10. return{

    11. setText:(id{

    12. var node=dom.byId;

    13. oldText[id=node.innerHTML;

    14. node=text;

    15. {

    16. var node=oldText;

    17. delete oldText;


    define 方法引用了必要的类,就像java 中的 import;并且还包含了对业务逻辑的实现,并通过return来返回,以上就是myModule.js文件的全部内容。那么在html页面里,通过dojo.require来加载上面的js代码,


    1. /Require the module we just created

    2. require["demo/myModule"(myModule/Use our module to change thetextin the greeting

    3. myModule.setText"greeting""Hello Dojo!"/Afterafew secondstextto its original state

    4. setTimeout(function{

    5. myModule.restoreText;


    上面的代码通常放在内执行。
    demo/myModule指的demo/myModule.js,有关路径问题参看这里:Dojo 学习(0): require的路径问题
    加载成功后就可以通过 myModule.setText 这样的方式来调用了。
    在这里暂且先总结为:dojo.define 方法仅用于定义和声明,dojo.require 方法仅用于异步加载js文件


    dojo类机制简介

    随着AJAX和RIA技术的发展,JavaScript被广泛的使用,并在开发中发挥着越来越重要的作用。JavaScript提供了特有的类机制,但是在语法习惯上与传统面向对象的语言有很大的不同,这使得不少的JavaScript开发人员感到比较迷惑,而dojo作为功能强大的JavaScript类库,有功能完整的类机制实现。本文将通过实例介绍的类机制,这是提供的一种强大和灵活的功能,其dijit UI组件框架也是以此为基础实现的。

    1. 使用dojo定义类

    声明类是通过.declare()方法来实现的,如我们想要定义一个名为com.levinzhang.Person的类,该类有name、age属性和getName、getAge方法:

    1. "com.levinzhang.Person"{

    2. name:nullageagethis.=.age=age;

    3. }{

    4. return;

    5. }

    6. })

    除了前面提到的属性的和方法以外,在代码中我们还定义了一个名为constructor的方法,这个方法在的类机制中至关重要,当我们实例化该类得到对象的时候,该方法将会被调用,从而完成初始化的操作。


    dojo的declare接受三个参数,分别为类的名称、要继承的父类以及该类的属性和方法。实例化类的语法也很简洁,与实例化普通的JavaScript类并无分别:

    		
    		
    			varperson=newcom.levinzhang.Person("levinzhang",30);	
    		
    			alert(person.getName());//将会提示出levinzhang		
    
    	

    2. 实现静态变量

    在常见的面向对象语言中,经常会使用到类层次的静态变量,而通过定义的类也能实现静态变量的需求,不过态变量仅限于数组和对象类型。

    		
    		
    			staticInfo:{count:0},constructor:function(name,age){
    		
    			this.name=name;
    		
    			this.age=age;
    		
    			++this.staticInfo.count;
    		
    			}		
    
    	

    如上所示,如果定义了数组和对象,而没有在构造方法中进行修改的话,这个对象将会成为该类的静态属性,测试代码如下:

    		
    		
    			varperson=newcom.levinzhang.Person("levinzhang",30);
    		
    			alert(person.staticInfo.count);//此时将会提示出1
    		
    			varperson2=newcom.levinzhang.Person("levin",30);
    		
    			alert(person2.staticInfo.count);//此时将会提示出2		
    
    	

    需要注意的两点是:1)对于原始类型的变量如数字、布尔值和字符串,的类机制并没有提供实现静态属性的功能;2)如果定义的数组或对象属性在constructor方法中被重新赋值,那么该属性将不再是静态属性,而是每个实例化对象都持有一份属于自己的备份了。

    3. 使用实现继承

    在JavaScript中没有直接实现继承的关键字,因此关于继承有多种的实现方式,代表性的是类式继承原型式继承,但是不管哪种继承方式都需要开发人员对JavaScript语言本身有着很深厚的了解。对JavaScript的继承机制进行了很好的封装,可以实现功能强大的类定义,我们将对一些常见的功能进行介绍。

    .declare方法中的第二个参数,是指明要继承的父类的,该参数可以为null(要定义的类没有父类)、单个类(要定义的类继承自一个父类)或数组(要定义的类继承自多个父类)。

    1) 单继承

    我们要定义一个名为com.levinzhang.Employee 的类,继承自com.levinzhang.Person,并要添加名为workExperience的属性、重写getName方法等功能:

    1. "com.levinzhang.Employee".levinzhang.Person{

    2. workExperience.workExperience=workExperience{

    3. return"Employee:"+{

    4. return 5000)


    在以上的代码中,我们定义的com.levinzhang.Employee继承了com.levinzhang.Person并添加了自定义的方法。测试代码如下:
    		
    			varemployee=newcom.levinzhang.Employee("levin",30,4);
    		
    			alert(employee.getName());//将提示出Employee:levin	
    		
    			alert(employee.getWorkExperience());//将提示出4	
    		
    			alert(employee.getAge());//将提示出30		
    
    	

    可以看到在Employee的实例中,我们能够调用父类中定义的方法。而在类的constructor初始化方法中,我们并没有调用父类相关的方法,但是我们成功初始化了name和age两个属性,这是因为会自动调用父类的初始化方法,完成继承要求的相关初始化工作。

    2) 多继承

    dojo支持多继承的功能,实现了被Python和很多支持多继承语言使用的C3算法。使用的多继承功能时,需要注意的是:只有数组中的第一个元素会作为真正的父类,而其它的元素则是通过mixin的方式进行属性添加以构建原型链的。

    如我们需要定义一个类来表示公司股票持有者(com.levinzhang.Shareholder),而公司员工可能也会持有股票,于是我们定义一个名为com.levinzhang.ShareholderEmployee的类继承自com.levinzhang.Shareholder和com.levinzhang.Employee。

    dojo.declare("com.levinzhang.Shareholder",com.levinzhang.Person,{
    share:null,constructor:function(args){
    this.share=args.share;
    },getShare:function(){
    returnthis.share;
    }
    });dojo.declare("com.levinzhang.ShareholderEmployee",[com.levinzhang.Employee,com.levinzhang.Shareholder],{
    getInfo:function(){
    alert("I'manEmployeewithstock.Myshareis"+this.getShare()+"."+"Mynameis"+this.getName()+".");
    }
    });

    在以上的代码中,我们调整了原有的初始化传入参数的格式,由传入多个参数改为传入一个简单JavaScript字面量对象的方式(原有的代码也要稍作调整),并通过多继承的方式实现了一个类用来描述持有股票的员工。测试代码如下:

    varshareholderEmployee=newcom.levinzhang.ShareholderEmployee({name:"levin",age:30,workExperience:4,share:300});
    shareholderEmployee.getInfo();
    //将会提示出“I'manEmployeewithstock.Myshareis300.MynameisEmployee:levin.”

    关于多继承的更多话题,请参考的文档资料

    3) 调用父类的方法

    在编程中,我们经常会遇到在子类的某个方法中需要调用父类的方法来协作完成功能。如我们定义名为com.levinzhang.Manager的 类,该类继承自com.levinzhang.Employee类,并重写getInput方法,Manager的收入分为两部分,一部分是与 com.levinzhang.Employee相同的固定收入,另一部分是与管理经验相关的其它收入,这样在定义Manager的时候,就需要调用父类 的方法,实现方式如下:

    		
    			dojo.declare("com.levinzhang.Manager",com.levinzhang.Employee,{
    		
    			manageExperience:null,constructor:function(args){
    		
    			this.manageExperience=args.manageExperience;
    		
    			},getInput:function(){
    		
    			varfromBase=this.inherited(arguments);
    		
    			returnfromBase+1000*this.manageExperience;
    		
    			}
    		
    			})	
    
    	

    从以上代码可以看到,通过inherited方法的使用,使得Manager可以调用父类的方法。测试代码如下:

    varmanager=newcom.levinzhang.Manager(
    {name:"levin",manageExperience:2});		
    			alert(manager.getInput());//7000		
    
    	

    在以上的测试代码中,getInput的返回值为7000,说明该值为子类和父类方法共同确定的。

    除了使用inherited来调用父类方法以外,从的1.4版本开始提供了链式调用父类方法的功能,能够通过设置自动调用父类的方法,并且支持类似于AOP的before或after配置(正在开发1.7版本,提供了更为丰富的AOP功能,我们将会持续关注)。

    4.Dojo类机制的其它功能

    除了以上介绍的类定义相关功能以外,还提供了许多的便利的工具类供使用。

    类所生成对象具有一些特有的属性和方法,常见的如isInstanceOf方法和declaredClass属性,isInstanceOf方法判定对象是否为某个类的实例,而declaredClass属性则能够表明该对象的声明类是什么。如:

    varmanager=newcom.levinzhang.Manager({name:"levin",manageExperience:2});
    alert(manager.isInstanceOf(com.levinzhang.Employee));//提示为true
    alert(manager.isInstanceOf(com.levinzhang.Person));//提示为true
    alert(manager.declaredClass);//提示为“com.levinzhang.Manager”

    类机制还涉及到的包管理等功能,限于篇幅,不再展开叙述,感兴趣的读者可以参考的在线文档或图书。

    5. 小结

    JavaScript本身的类机制比较复杂,对开发人员有着较高的要求,而提供了功能强大的类功能,有些降低了开发的难度。本文简单介绍了类机制的基本功能,包括类定义、继承、静态属性等,这是最基础也是最核心的内容之一,的许多高级功能都是基于此来实现的,因此了解这部分功能的使用方式甚至源码实现对于整体把握框架都大有裨益。

    参考资料:

    关于作者:

    张卫滨,关注企业级Java开发和RIA技术,个人博客:http://lengyun3566.iteye.com

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐


    我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易知道用户保存了什么,我希望当用户第一次看到网格时,网格处于不可编辑状态.当用户准备好后,他们可以单击编辑按钮,这将使网格的某些部分可编辑.然后,有一个保存或取消按钮可以保存更改或还原.在大多数情况下它是有效的.但
    我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以轻松打包为Web,Mobiles和可能的Standalone版本的方式来实现这一目标.我不想使用Flash.因此,我确信(无论如何我会听取建议)使用JavaScript和SVG.我正在对这个问题进行大量研究,但我很难把各个部分放在一起.我知道Raphae
    我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部件–我在表单中使用–将固定格式(JavaScript基本格式)的实数值(例如:12.56)设置为HTML表单输入字段(但根据浏览器区域设置显示/编辑它们,所以用户总是看到格式正确的数字).另一方面,Grails期望输入字段根据浏览器
    1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforjavaScript的学习历程,本篇将从最开始的arcgisapiforjavaScript部署开始,个人声明:博文不在传道受业解惑,旨在方便日后复习查阅。由于是自学,文章中可能会出现一些纰漏,请留言指出,不必留有情面哦!2.下载ArcGISforDe
    我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑:Thedeclarefunctionisdefinedinthedojo/_base/declaremodule.declareacceptsthreearguments:className,superClass,andproperties.ClassNameTheclassNameargumentrepresentsthenameofthec
    我的团队由更多的java人员和JavaScript经验丰富组成.我知道这个问题曾多次被问到,但为了弄清楚我的事实,我需要澄清一些事情,因为我在客户端技术方面的经验非常有限.我们决定使用GWT而不是纯JavaScript框架构建我们的解决方案(假设有更多的Java经验).这些是支持我的决定的事实.>
    路由dojo/framework/srcouting/README.mdcommitb682b06ace25eea86d190e56dd81042565b35ed1Dojo应用程序的路由路由FeaturesRoute配置路径参数RouterHistoryManagersHashHistoryStateHistoryMemoryHistoryOutletEventRouterContextInjectionOutl
    请原谅我的无知,因为我对jquery并不熟悉.是否有dojo.connect()的等价物?我找到了这个解决方案:http:/hink-robot.com/2009/06/hitch-object-oriented-event-handlers-with-jquery/但是没有断开功能!你知道jquery的其他解决方案吗?有jquery.connect但这个插件在我的测试中不起作用.
    与java类一样,在dojo里也可以定义constructor 构造函数,在创建一个实例时可以对需要的属性进行初始化。//定义一个类mqsy_yjvar mqsy_yj=declare(null,{     //thedefaultusername    username: "yanjun",          //theconstructor   
    我一直在寻找一些最佳实践,并想知道Dojo是否具有框架特定的最佳实践,还是最好只使用通用的Javascript标准?特别是我主要是寻找一些功能和类评论的指导方针?解决方法:对于初学者来说,这是项目的风格指南:DojoStyleGuide
    我有’05/17/2010’的价值我想通过使用dojo.date.locale将其作为“2010年5月17日”.我尝试过使用dojo.date.locale.parse,如下所示:x='05/17/2010'varx=dojo.date.locale.parse(x,{datePattern:"MM/dd/yyyy",selector:"date"});alert(x)这并没有给我所需的日期
    我正在尝试创建一个包含函数的dojo类,这些函数又调用此类中的其他函数,如下所示:dojo.provide("my.drawing");dojo.declare("my.drawing",null,{constructor:function(/*Object*/args){dojo.safeMixin(this,args);this.container=args[0];
    我知道你可以使用jQuery.noConflict为jQuery做这件事.有没有办法与Dojo做类似的事情?解决方法:我相信你可以.有关在页面上运行多个版本的Dojo,请参阅thispage.它很繁琐,但似乎是你正在寻找的东西.一般来说,Dojo和jQuery都非常小心,不会破坏彼此或其他任何人的变量名.
    我有一个EnhancedGrid,用户经常使用复杂的过滤器.有没有办法允许用户保存或标记过滤器,以便将来可以轻松地重新应用它?我知道我可以通过编程方式设置过滤器,但我无法预测用户想要的过滤器.谢谢!编辑:自己做了一些进展…使用grid.getFilter()返回过滤器的JSON表示,然后使用json.strin
    我有这个代码:dojo.declare("City",null,{constructor:function(cityid,cityinfo){}});dojo.declare("TPolyline",GPolyline,{constructor:function(points,color){},initialize:function(map){});应该是什
    我遇到的问题是我的所有javascript错误似乎来自dojo.xd.js或子模块.我正在使用chrome调试器和许多dijit功能,如dijit.declaration和dojo.parser.这有点烦人,因为它很难找到简单的错误或滑倒.我希望我可以添加一个选项,允许我的调试器在我的非dojo代码中显示选项会发生的位置.我是
    我正在使用DojoToolkit数字/解析函数来处理格式化和使用ICU模式语法解析字符串.有没有人知道有可能采取任意ICU模式字符串并以某种方式使用Dojo(或其他)库将其分解为它的部分(例如,对于数字模式,它可以被分解为小数位数,数千个分组等…).我希望这样做,而不需要让我的代码密切了
    我有两个看似相关的问题,访问在不同的地方定义的javascript函数.我遇到的第一个问题是调用我在firgbug或safari控制台中定义的函数.我定义了一个名为getRed的函数,如下所示:functiongetRed(row,col){//dosomethingstuffandreturntheredvalueasa
    我想添加一个在Ajax调用中指定的外部样式表.我已经找到了一种方法来使用jQuery(参见下面的示例),但是我需要使该方法适应dojoJavaScript框架.JQuery示例$('head').append('<linkrel="stylesheet"type="text/css"href="lightbox_stylesheet.css">');谢谢.解决方法:一旦你
    我正在尝试使用dojo.connect将onMouseDown事件连接到图像,如:dojo.connect(dojo.byId("workpic"),"onMouseDown",workpicDown);functionworkpicDown(){alert("mousedown");}类似的代码几行后,我将onMouse*事件连接到dojo.body确实完全正常工作.但是当我点击图像时