Dojo学习之Class类

转载自:http://blog.csdn.net/lovecarpenter/article/details/53981357

1.引言

说到面向对象,我们就不得不提一下类,在原生的js中我们是不可以创建类的,没有class这个关键字,但是在dojo中,dojo自定义了一个模块叫做dojo/_base/declare,用这个模块我们可以创建自己的类,实现面向对象编程。在本篇博客中我们就来学习一下如何在我们应用程序中使用dojo/_base/declare创建类。

2.dojo中的类

首先我们先看一下dojo/_base/declare声明:

 
 
  • 1
  • 1
declare(classname,[],{})
  • declare的第一个参数是可选的,代表类的名称
  • declare的第二个参数代表类的继承关系,比如继承哪一个父类,可以看到:第二个参数是一个数组,所以dojo可以多继承
  • 第三个参数是一个对象,代表类的主体。

2.1创建一个简单的类

说完了类的继承,那么我们就创建一个非常简单的类:

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    var Person=declare("namespace.Person",null,{ name:function(name,age){ this.name=name; this.age=age; } });
    • 上述代码建立了一个Person类,没有父类,构造函数为constructor
    • 我们如何创建一个Person类的实例呢?代码:var p=new Person("wpx",20)

    上面的方法是很简单的一个类,但是有一个问题,如果类的属性特别多,那么我们构造函数里面的参数就会很多,有没有一种解决方法呢?答案是有的。现在看修改之后的代码。

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    (args){ declare.safeMixin(this,args); } });

    那么我们在创建类的实例时,应该怎么办呢?代码:

      
      
  • 1
  • 2
  • 3
  • 4
    • 1
    • 2
    • 3
    • 4
    var p=new Person({ name:"wpx",age:20 })

    此时可能有朋友问了,类名有什么作用呢??类名可以用作类的全局引用比如上面的Person类还可以这样定义实例:

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
    • 1
    • 2
    • 3
    • 4
    • 5
    new namespace.Person({ name:20 })

    2.2类和模块结合使用

    学过后台语言的人大多都习惯:一个类一个文件。这样的话有利于我们关于我们的js代码,那么在dojo中如何实现呢?代码如下:

    • person.js
      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    define(["dojo/_base/declare"],(declare){ return declare((){ return this.name+":"+this.age } }) })
    • 调用我们自定义的类
      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    require(["js/person"],102); box-sizing: border-box;">(Person) { new Person({ name:20 }); alert(p.toString()) });

    假设我们的类名是namespace.Person,我们还可以这样引用(注意和上面的区别),也就是全局引用:

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • () { new namespace.Person({ name:20 }); alert(p.toString()) });
    • 运行结果

    2.3关于类的继承

    关于类的继承如何使用,在此处不多说,如果想要了解更多类的高级使用请查看官网:
    dojo创建类

    3.需求

    在上面只是简单的介绍了一下如果创建类,如何使用类,那么现在我们从需求的方面说一下类的使用。

    3.1需求一

    假如我们新来了一个项目,然后项目经理说:小王,现在我想实现一个功能,提供一个点的坐标,然后给地图添加一个图标。你只需要给我一个接口就好了,具体怎么实现我不管。那么我们现在如何实现呢?
    思路:创建一个模块,然后模块里面有一个类,类有一个方法,方法可以给地图添加点图形就好了嘛。对的,但是有的同学会说,那么地图对象怎么来呢?答案是:我们可以通过构造函数传进来吗。

    • 代码实现
      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    define(["esri/graphic","esri/symbols/SimpleMarkerSymbol",0); box-sizing: border-box;">"esri/symbols/SimpleLineSymbol",0); box-sizing: border-box;">"dojo/colors",0); box-sizing: border-box;">"esri/layers/GraphicsLayer",136); box-sizing: border-box;">function (Graphic,SimpleMarkerSymbol,SimpleLineSymbol,Color,GraphicsLayer,declare){ return declare(//定义map对象,由外界传入 constructor: //提供方法用于添加点 addPoint:(point){ var lineSymbol=new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID,new Color([255,0,102); box-sizing: border-box;">0]),102); box-sizing: border-box;">2) var pSymbol = new SimpleMarkerSymbol(SimpleMarkerSymbol.STYLE_CROSS,102); box-sizing: border-box;">100,lineSymbol,102); box-sizing: border-box;">0.25])); var g=new Graphic(point,pSymbol); var layer=new GraphicsLayer(); layer.add(g) this.map.addLayer(layer); } }) })
    • 主页面:
      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    "esri/map",0); box-sizing: border-box;">"esri/layers/ArcGISDynamicMapServiceLayer",0); box-sizing: border-box;">"esri/geometry/Point",0); box-sizing: border-box;">"js/MyUtil",0); box-sizing: border-box;">"dojo/domReady!"],102); box-sizing: border-box;">(Map,ArcGISDynamicMapServiceLayer,Point,MyUtil) { var map=new Map("mapDiv") new Point( { x:"-107.13700471124938",y:"41.54667348528646",spatialReference:{ wkid:"4326" } }) new ArcGISDynamicMapServiceLayer("http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"); map.addLayer(layer); var util=new MyUtil({ map:map }); util.addPoint(p); });

    3.2需求二(很重要)

    我们实现了需求一,但是突然有一天项目经理把你找来说:小王啊,我们的需求变了啊,上次的功能可能要改一改,我不提供点了,我想进行交互绘制图形。但是呢,我绘制的图形不添加到地图中,我想将它返回给我

    3.2.1代码实现

    这时候大家会想,这还不简单呢。我们直接直接绘制完图像,然后获得绘制的几何形状,直接return不就好了吗。我们的思路是这样的:
    * 创建一个模块
    * 模块中有一个getPoint方法,调取getPoint方法获得点的坐标

    但是问题来了,我们先观察一下我们的代码:

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • getPoint:() { on(this.toobar,0); box-sizing: border-box;">"draw-complete",136); box-sizing: border-box;">this.showResult); },showResult:(result){ var geometry=result.geometry; }

    观察代码我们发现问题了:我们调用了getPoint方法,但是呢,几何形状是在showResult方法中获得的,我们根本不能return,所以一开始我们的思路是错误的。

    出现问题,那么我们就应该去解决问题,我们应该如何将我们的数据返回呢?答案是利用回调方法。我们在类中给外界提供一个接口,这个接口是一个函数,通过这个函数将我们的数据返回。所以我们是这样实现的

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    define(["dojo/on",0); box-sizing: border-box;">"dojo/_base/declare",0); box-sizing: border-box;">"esri/toolbars/draw"],102); box-sizing: border-box;">(on,declare,Draw){ "mydraw",[],0); box-sizing: border-box;">//当前Map对象 toobar://用于回调,传数据 constructor:(args) { declare.safeMixin(this.toobar = new Draw(this.map,{ showTooltips: true }); this.toobar.activate(Draw.POINT); },getPoint:(callback) { this.init(); this.callback=callback; on(this.callback(result.geometry); } }) });
    • 我们调用
      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    "dojo/dom",0); box-sizing: border-box;">"js/mydraw",dom,MyDraw) { "http://sampleserver6.arcgisonline.com/arcgis/rest/services/USA/MapServer"); map.addLayer(layer); dom.byId("btn").onclick=(){ var my=new MyDraw({ map:map }); my.getPoint((g) { alert(g) }) } });

    3.2.2程序出错

    问题又来了,我们的思路没问题了,但是一运行,程序报错了

    仔细排错,发现this没有callback属性

    这时候我们就纳闷了,到底哪里出错了呢,我们明明定义了callback啊,然后继续挑错发现了更有趣的事情

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    getPoint:this.callback=callback; //此处的this是我们的mydraw类 on((result){ //此处this的指向变了,大家可以debug看一下 this.callback(result.geometry); }

    不知道大家还记不记得,在js中this关键字十分灵活,我们知道在类中this的使用是不可避免的,使用频率会非常高,我们还说过,在函数的调用是,我们是可以控制this的指向的,在dojo中提供了一个模块叫做dojo/_base/lang,使用该模块我们可以控制this的指向,那么我们应该怎么用呢??修改此错误,只需要修改一个地方便可

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • getPoint:this.showResult)); },

    注意:我使用on绑定事件的时候:控制了this的指向,在getPoint函数中this是我们的mydraw类,所以让调用showResult函数时,控制this为mydraw即可。

    3.2.3程序运行

    在次运行程序,终于成功了:

    3.3 需求三

    需求三就很简单了,有的同学在使用dojo的时候可能还会使用jQuery中类库(其实没必要,dojo已经很强大了),那么我们应该怎么办呢?如何在我们自己的模块中使用jquery呢?代码如下

      
      
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • define([declare(null,{ $:(args){ declare.safeMixin(this,args); } }) })

    在使用我们类的时候(假设我们的Person):

      
      
  • 1
  • 2
  • 3
    • 1
    • 2
    • 3
    new Person({ $:$ });

    原理就是将我们全局的$传给我们自定义模块。

    4.再次介绍require加载模块

    首先我们看一下我们加载的顺序:

    • 第一:如果我们有自定义模块,那么通过dojoConfig配置我们自定义模块的路径
    • 第二:加载init的js文件(注意一定要在dojoConfig加载)
    • 第三:require是按照顺序加载的,比如我require首先加载的是dijit/registry,那么后面的function里面就写一个变量代表dijit/registry模块,此时变量的名称无所谓,仅仅代表该模块,但是注意:图中的①处代表的是一个js文件,图中的②是一个自定义的变量(用来代表该模块)。
    • 第四:大家注意到,我require中的第一个参数有六个模块,但是function中,却只有四个变量。此处说明:如果我们在funtcion函数中用不到该模块(注意是在function中用不到,并不是说明其他地方用不到),那么我们尽量将该模块往后放。
    • 第五:在此声明:图中的①处代表的是一个js文件,图中的②是一个自定义的变量,既然是一个自定义变量,那么就意味着我们可以随便写(用来代表前面的js文件)。可能有人问,一个文件夹下面有很多的类,我们随便写不就乱套了吗?这种情况是不存在的。在此声明:图中的①处代表的是一个js路径,同一个文件夹下面是不可能存在同名文件的。

    4.总结

    在此篇博客中,主要说了

    • 如何创建类,如何使用类,其中我们可以用define方法让我们的类是一个文件,便于管理。
    • 在类中如何利用回调函数返回数据
    • 如何在类中使用类外变量(可以通过构造函数传进来)
    • 在类中正确的使用dojo/_base/lang模块,控制我们的this关键字
    • 重新介绍了require的加载过程
    • 注意我们定义了很多的类和模块,但是我们程序的入口确只有一个

    4.1本博客代码的下载地址:dojo_class

    相关文章

    我有一个网格,可以根据更大的树结构编辑小块数据.为了更容易...
    我即将开始开发一款教育性的视频游戏.我已经决定以一种我可以...
    我正在使用带有Grails2.3.9的Dojo1.9.DojoNumberTextBox小部...
    1.引言鉴于个人需求的转变,本系列将记录自学arcgisapiforja...
    我正在阅读使用dojo’sdeclare进行类创建的语法.描述令人困惑...
    我的团队由更多的java人员和JavaScript经验丰富组成.我知道这...