关键词搜索

源码搜索 ×
×

dojo中的类

发布2022-12-05浏览519次

详情内容

使用arcgis api for js 4.*进行地图的web前端开发,就不得不与dojo打交道。dojo是一个框架,自成体系,比如它对类的支持,有自己的一套。众所周知,js不是面向对象语言,没有类这一说,都是用函数来模拟类。

那么dojo里的类是怎么样的呢?

1、定义(声明)类

用declare。

declare(基类,类定义)
  • 1

第一个参数是基类,单个基类或多个基类组成的数组,如果没有基类,则以null或空数组“[ ]”代替。比如下面:

var A = declare(null, {
  constructor: function(name, age, residence){
    this.name = name;
    this.age = age;
    this.residence = residence;
  }
});

var a = new A("孙悟空",48000,"花果山水帘洞");
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

类定义,总体上看是一个json。构造函数,各种方法,都是json元素。

constructor,顾名思义,是构造函数。注意name、age、residence并没有声明,直接使用,作为实例的属性。这样不管new多少个A实例,实例之间的属性都不会互相影响。

但我之前不懂,将变量声明在declare之外,new出来的实例,变量居然是共用的。看上去,变量放在declare外部,就相当于全局静态变量
在这里插入图片描述
注:图中的代码,是dojo比较老旧的版本,所以declare有三个参数。

2、继承

//员工类
define(["dojo/_base/declare", "my/Person"], function(declare, Person){
  return declare(Person, {
    constructor: function(name, age, residence, salary){
      // The "constructor" method is special: the parent class (Person)
      // constructor is called automatically before this one.

      this.salary = salary;
    },

    askForRaise: function(){
      return this.salary * 0.02;
    }
  });
});

//领导类
define(["dojo/_base/declare", 'my/Employee'], function(declare, Employee){
  return declare(Employee, {
    askForRaise: function(){
      return this.salary * 0.25;
    }
  });
});

//使用员工类和领导类
require(["my/Employee", "my/Boss"], function(Employee, Boss){
  var kathryn = new Boss("Kathryn", 26, "Minnesota", 9000),
      matt    = new Employee("Matt", 33, "California", 1000);

  console.log(kathryn.askForRaise(), matt.askForRaise()); // 2250, 20
});

  • 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
  • 29
  • 30
  • 31
  • 32
  • 33

3、类的链式初始化

就是创建dojo的类实例时,初始化默认是从最老的祖宗开始,一代接一代的依次初始化。

require(["dojo/_base/declare"], function(declare){
  var A = declare(null, {
    constructor: function(){ console.log("A"); }
  });

  var B = declare(A, {
    constructor: function(){ console.log("B"); }
  });

  var C = declare(B, {
    constructor: function(){ console.log("C"); }
  });

  new C();
});

// prints:
// A
// B
// C
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

如果想打断这种链式初始化,如:

require(["dojo/_base/declare"], function(declare){
  var A = declare(null, {
    constructor: function(){
      console.log("A");
    }
  });

  var B = declare(A, {
    "-chains-": {//声明链式初始化为手动模式,其实就是打断了链式传播。好滑稽的方法
      constructor: "manual"
    },
    constructor: function(){
      console.log("B");
    }
  });

  var C = declare(B, {
    constructor: function(){
      console.log("C - 1");
      this.inherited(arguments);//显式调用父类初始化,爷爷或更老的祖宗就不必了
      console.log("C - 2");
    }
  });

  var x = new C();
});

// prints:
// C - 1
// B
// C - 2
  • 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
  • 29
  • 30
  • 31

4、扩展类

如果要扩展一个类,可以用 类.extend(扩展部分定义)。注意扩展部分是扩展,不是完全覆盖。只有重复部分才会被覆盖,原先没有的,则新增到类里。所谓有则改之,无则增加。类修改后,所有的实例都受到影响。

extend返回扩展后的类。

示例如下:

require(["dojo/_base/declare"], function(declare){
  var A = declare(null, {
    m1: function(){
      // ...
    }
  });

  A.extend({
    m1: function(){
      // this method will replace the original method
      // ...
    },

    m2: function(){
      // ...
    }
  });

  var x = new A();
  a.m1();
  a.m2();
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

5、派生类

多说无益,直接看代码

require(["dojo/_base/declare"], function(declare){
  var A = declare(null, {
     m1: function(){},
     s1: "bar"
  });
  var B = declare(null, {
      m2: function(){},
      s2: "foo"
  });
  var C = declare(null, {});
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

对于上述代码,下面2种方法的效果是一样的:
1)方式一

var D1 = A.createSubclass([B, C], {
    m1: function(){},
    d1: 42
});
var d1 = new D1();
  • 1
  • 2
  • 3
  • 4
  • 5

2)方式二

var D1 = declare([A, B, C], {
    m1: function(){},
    d1: 42
});
var d1 = new D1();

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

其中方式一就使用了createSubclass。由A派生,同时继承B和C。等同于同时继承A、B、C。
createSubclass有两个参数,参数一为基类,参数二为注入新类的定义。所谓注入,即有则改之,无则增加,参考 4、扩展类。

createSubclass与extend的区别,在于extend只是对现有类进行扩展,而createSubclass是继承并派生出一个新类。

6、调用父类方法

inherited()

这个方法十分令人费解。它最多有三个参数。

第一个参数是方法名,可选。不指定,调用的是父类的当前方法的同名方法(?)

第二个参数是arguments,是个伪变量,不用声明。据说用于“内省(introspection)”,不知道是什么意思。反正名字不能改把它当作保留字看待。

第三个参数是传递的参数,如果没有指定,第二个参数arguments就发挥作用。但如果为[“true”],则返回父类方法的定义,而不执行。

如果没有父类方法,则返回undefined。

require(["dojo/_base/lang", "dojo/_base/declare"], function(lang, declare){
  var A = declare(null, {
    m1: function(){
      // ...
    },
    m2: function(){
      // ...
    },
    m3: function(){
      // ...
    },
    m4: function(){
      // ...
    },
    m5: function(){
      // ...
    }
  });

  var B = declare(A, {
    m1: function(){
      // simple super call with the same arguments
      this.inherited(arguments);
      // super call with new arguments
      this.inherited(arguments, [1, 2, 3]);
    }
  });

  // extend B using extend()
  B.extend({
    m2: function(){
      // this method is going to be properly annotated =>
      // we can use the same form of this.inherited() as
      // normal methods:
      // simple super call with the same arguments
      this.inherited(arguments);
      // super call with new arguments
      this.inherited(arguments, ["a"]);
    }
  });

  // extend B using lang.extend()
  lang.extend(B, {
    m3: function(){
      // this method is not annotated =>
      // we should supply its name when calling
      // a superclass:
      // simple super call with the same arguments
      this.inherited("m3", arguments);
      // super call with new arguments
      this.inherited("m3", arguments, ["a"]);
    }
  });

  // let's create an instance
  var x = new B();
  x.m1();
  x.m2();
  x.m3();
  x.m4(); // A.m4() is called
  x.m5(); // A.m5() is called

  // add a method on the fly using declare.safeMixin()
  declare.safeMixin(x, {
    m4: function(){
      // this method is going to be properly annotated =>
      // we can use the same form of this.inherited() as
      // normal methods:
      // simple super call with the same arguments
      this.inherited(arguments);
      // super call with new arguments
      this.inherited(arguments, ["a"]);
    }
  });

  // add a method on the fly
  x.m5 = function(){
    // this method is not annotated =>
    // we should supply its name when calling
    // a superclass:
    // simple super call with the same arguments
    this.inherited("m5", arguments);
    // super call with new arguments
    this.inherited("m5", arguments, ["a"]);
  };

  x.m4(); // our instance-specific method is called
  x.m5(); // our instance-specific method is called
});

  • 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
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

7、在arcgis api for js中的应用

示例

define([
  "dojo/_base/declare",
  "esri/geometry/support/webMercatorUtils",
  "./WebGlLayer",
], function (declare, webMercatorUtils, WebGlLayer) {
  return declare(null, {
    constructor: function (mapView) {
      this.core = new Core(mapView);
    },
    draw: function (data, options) {
      this.core.load(data, options);
    },
    clear: function () {
      this.core.clear();
    },
  });

  function Core(mapView) {
  	。。。
  }
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

以上仅为dojo类定义及操作的部分内容。dojo只是一个框架,对类的定义和实现自成一家,有些地方十分有趣。因为前端要用到arcgis api for js,依赖dojo,了解即可,不作深究。dojo有关类的完整阐述,见参考文章。

参考文章:
https://dojotoolkit.org/reference-guide/1.9/dojo/_base/declare.html

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载