Classy JavaScript with dojo.declare
dojo.declare方法是Dojo工具包中类创建的基础。dojo.declare允许多重继承,允许开发人员创建灵活的代码,避免编写相同的代码例程。Dojo,Dijit 模块都是使用dojo.declare的。在这个教程中。您将了解为什么你也应该这么做。
Getting Started
在深入dojo.declare创建类之前,有一些关键的概念复习下。
dojo.provide
dojo.provide 申明使资源包被包含,可以在文件中使用。这些资源可能是一系列的类,函数,或者是一个拉入其他资料的dojo.require代码块。dojo.privide在其中 起到了关键的作用让其他窗口小部件和内部资源页面知道给定类的存在。
dojo.require
dojo.require
在类创建角色中是提供新的类的依赖项。一个资源必须加载新类来继承它
Basic Dojo Class Creation with Dojo
dojo.declare 方法被定义base dojo对象里。所以没有额外的依赖关系来加载。dojo.declare 接受三个参数,类名、父类、和属性
ClassName
className参数表示类的名称,其中包括名称空间,要创建的。 被命名的类被放置在全局范围
className
通过名称空间也能代表继承链。
命名类
// Create a new class named "mynamespace.myClass"
dojo.declare("mynamespace.myClass",null,{
// Custom properties and methods here
});
一个名叫myClass类,现在全局中是可用的应用程序。
匿名类
// Create a scoped, anonymous class
var myClass = dojo.declare(null,{
// Custom properties and methods here
});
myClass目前仅能在给定的范围中使用。
SuperClass(es)
父类参数可以为null、一个现有的类或者现有类的数组。如果一个新类继承了不止一个类,第一个类在列表会基本原型,其余的将被视为“mixinx”
没有继承关系的类
// Create a new class named "mynamespace.myClass"
dojo.declare("mynamespace.myClass",null,{
// Custom properties and methods here
});
”null“意味着这类没有类继承。
有继承关系的类
// Create a new class named "mynamespace.myClass"
dojo.declare("mynamespace.myClass",mynamespace.myParentClass,{
// mynamespace.myClass now has all of mynamespace.myParentClass's properties and methods
// These properties and methods override parent's
});
新类mynamespace.myClass将继承mynamespace.myParentClass
's的方法和属性。后面的章节将介绍,父类的方法和和属性通过第三个参数的定义的键值重写。
继承多个类
// Create a new class named "mynamespace.myClass"
dojo.declare("mynamespace.myClass",[
mynamespace.myParentClass,
mynamespace.myOtherClass,
mynamespace.myMixinClass
],
{
// mynamespace.myClass now has all of the properties and methods from:
// mynamespace.myParentClass, mynamespace.myOtherClass, and mynamespace.myMixinClass
});
一个数组类的
象征多重继承。属性和方法是继承了从左到右。第一个类数组作为基本原型,那么随后的类是混入到这个类。
*如果一个指定的属性或方法在多个继承类中存在,属性或方法属于最后一个使用继承类。
Properties and Methods Object
dojo.declare的最后一个参数是一个
包含方法和属性的对象。
通过这个提供属性和方法的对象会覆盖继承类具有相同的特性同名的函数和属性。
自定义属性和方法
// Class with custom properties and methods
dojo.declare("mynamespace.Class",[mynamespace.MyParentClass],{
// Any property
myProperty1: 12,
// Another
myOtherProperty: "Hello",
// A method
myMethod: function() {
// Perform any functionality here
return result;
}
})
例如:基本的类创建和继承
以下代码是
Dijit内创建的dijit.form.CurrencyTextBox小部件:
dojo.declare(
"dijit.form.CurrencyTextBox",
dijit.form.NumberTextBox,
{
currency: "",
baseClass: "dijitTextBox dijitCurrencyTextBox",
regExpGen: function(constraints){
// if focused, accept either currency data or NumberTextBox format
return '(' + (this._focused? this.inherited(arguments, [ dojo.mixin({}, constraints, this.editOptions) ]) + '|' : '')
+ dojo.currency.regexp(constraints) + ')';
},
// Override NumberTextBox._formatter to deal with currencies, ex: converts "123.45" to "$123.45"
_formatter: dojo.currency.format,
_parser: dojo.currency.parse,
parse: function(/*String*/ value, /*Object*/ constraints){
// summary:
// Parses string value as a Currency, according to the constraints object
// tags:
// protected extension
var v = this.inherited(arguments);
if(isNaN(v) && /\d+/.test(value)){ // currency parse failed, but it could be because they are using NumberTextBox format so try its parse
v = dojo.hitch(dojo.mixin({}, this, { _parser: dijit.form.NumberTextBox.prototype._parser }), "inherited")(arguments);
}
return v;
},
_setConstraintsAttr: function(/*Object*/ constraints){
if(!constraints.currency && this.currency){
constraints.currency = this.currency;
}
this.inherited(arguments, [ dojo.currency._mixInDefaults(dojo.mixin(constraints, { exponent: false })) ]); // get places
}
}
);
从上面的代码片段容易看出
- 类名是:
dijit.form.CurrencyTextBox
- 父类是:dijit.form.NumberTextBox
- 类设置了许多用户自定义的方法和属性
通过学习构造函数方法让我们更深入地类创建。
The constructor Method
一旦定义了特殊的类方法构造方法。构造方法在类实例化时被执行,作用于这个类范围。这意味着“this”这个关键字代表这个类实例,不是原始类。构造函数方法也接受任何数量的特定参数。// Create a new class
dojo.declare("mynamespace.Twitter",null,{
// The default username
username: "defaultUser",
// The constructor
constructor: function(args) {
dojo.safeMixin(this,args);
}
});
采取以下实例创建:
var myInstance = new mynamespace.Twitter();
由于没有特定的设置提供给类实例所以这个实例属性‘username’的值为‘defaultUser’。利用safeMixin方法,提供一个用户名参数:
var myInstance = new mynamespace.Twitter({
username: "sitepen"
});
现在实例属性username值为‘sitepen’!
dojo.safeMixin在类创建和继承也
是有用的。像API文档描述的:
"此功能有点像lang._mixin功能,但它将被用于构造函数中。 this.inherited()与declare.safeMixin混在功能,可以像使用正常的方法一样,它可以在构造方法中使用this.inherited()"
继承
就像上面所说的,类的继承是从左至右的,并且属性和方法可能会被覆盖
上面继承类的结果
this.inherted
全部的重写父类的方法当然是可行的,但有的时候在构造函数中使用继承链可以有效的保护原有的功能。这也就是this.iinherited(XXX)这个方法的作用。这个方法调用了父类中的同名的方法
this.inheried方法可以在子类中的任何时候进行调用。
结论
declare是创建模块所需要的非常重要的方法。重用declare可以重创建出更多更复杂的模块结构。