Creating Classes 创建类
The dojo/_base/declare
module is the foundation of class creation within the Dojo Toolkit. declare
allows for multiple inheritance to allow developers to create flexible code and avoid writing the same code routines. Dojo, Dijit, and Dojox modules all use declare
; in this tutorial, you'll learn why you should too.
dojo/_base/declare模块是dojo Toolkit定义的创建类的函数。decleare允许开发者使用多重集成机制,以避免编写重复代码。dojo,dijit以及dojox模块定义都是用declare。在本教程中,你将学习如何定义类。
Getting Started 开始
Make sure you have reviewed the concepts presented in the modules tutorial.
确定你已经了解了在模块教程中出现的相关概念。
Basic Dojo Class Creation with Dojo 使用dojo创建的最基本的类
The declare
function is defined in the dojo/_base/declare
module. declare
accepts three arguments: className
, superClass
, and properties
.
declare函数定义在dojo/_base/declare模块中,declare接受三个参数:className、SuperClass以及属性集合。
ClassName 类名
The className
argument represents the name of the class, including the namespace, to be created. Named classes are placed within the global scope. The className
can also represent the inheritance chain via the namespace.
className参数代表着类的名称,包含命名空间。命名的类位于全局作用域中。className也可以通过命名空间标识其归属及继承关系等。
Named Class 命名类
/ Create a new class named "mynamespace.MyClass"
declare("mynamespace.MyClass", null, { // Custom properties and methods here });
A class named mynamespace.MyClass
is now globally available within the application.
一个命名为mynamespace.MyClass
在应用中已经是一个全局变量。
Named classes should only be created if they will be used with the Dojo parser. All other classes should omit the className
parameter.
当一个类需要dojo进行解析的时候,必须定义成命名类,其他的类可以省略className参数。
"Anonymous" Class 匿名类
// Create a scoped, anonymous class
var MyClass = declare(null, { // Custom properties and methods here });
The MyClass
is now only available within its given scope.
现在MyClass只有在定义它的作用域内可用。
SuperClass(es) 超类
The SuperClass argument can be null
, one existing class, or an array of existing classes. If a new class inherits from more than one class, the first class in the list will be the base prototype, the rest will be considered "mixins".
超类参数可以为空、一个已经存在的类、或者多个存在的类组成的集合。如果一个新类在定义的时候集成了多个类,那么多个类中的第一个类将是基础原型类,其他的类被认为是混入类。
Class with No Inheritance 没有继承任何类的类
var MyClass = declare(null, { // Custom properties and methods here });
null
signifies that this class has no classes to inherit from.
null的意思就是该类没有继承其他任何类。
Class Inheriting from Another Class 类继承了其他类
var MySubClass = declare(MyClass, { // MySubClass now has all of MyClass's properties and methods
// These properties and methods override parent's });
The new MySubClass
will inherit MyClass
's properties and methods. A parent class' method or property can be overridden by adding its key with a new definition within the third argument, which will be explained shortly.
新的MySubClass将会继承MyClass定义的属性和函数。
Class with Multiple Inheritance 多继承的类
var MyMultiSubClass = declare([
MySubClass,
MyOtherClass,
MyMixinClass
],{ // MyMultiSubClass now has all of the properties and methods from:
// MySubClass, MyOtherClass, and MyMixinClass });
An array of classes signifies multiple inheritance. Properties and methods are inherited from left to right. The first class in the array serves as the base prototype, then the subsequent classes are mixins to that class.
一个类集合意味着多继承。从左到右,这些类的属性和函数将被继承。类集合中的第一个类承担基础原型的角色,后面其他的类担任混入类的角色。
If a property or method is specified in more than one inherited class, the property or method from the last inherited class is used.
如果属性或者方法在继承的不止一个类中都有定义,那么dojo将会认为最后一个定义是有效的。
Properties and Methods Object
The last argument of declare
is an object containing methods and properties for the class prototype. Properties and methods provided via this argument will override their same namesake if inherited classes have the same properties.
最后一个参数是作为类的属性存在,该参数是一个对象,包含了一些属性和方法。如果该对象中定义的属性和方法和继承类中的有冲突,那么本属性和函数是有效的,继承类中无效。
Custom Properties and Methods
/ Class with custom properties and methods
var MyClass = declare(MyParentClass, {
// Any property
myProperty1: 12,
// Another
myOtherProperty: "Hello",
// A method
myMethod: function(){ // Perform any functionality here return result;
}
});
Example: Basic Class Creation and Inheritance
例子:使用继承,创建一个基础类
The following code creates a widget that inherits from dijit/form/Button
:
下面的例子,我们创建了一个继承dijit/form/Button的小部件类:
define([
"dojo/_base/declare",
"dijit/form/Button"
], function(declare, Button){
return declare("mynamespace.Button", Button, {
label: "My Button",
onClick: function(evt){
console.log("I was clicked!");
this.inherited(arguments);
}
});
});
From the snippet above, it's easy to conclude:
通过上面的小片段,我们得到以下结论:
- The class' name is
mynamespace.Button
- The class may be referenced by the globally available
mynamespace.Button
or from the module's return value - The class inherits from
dijit/form/Button
(and thus Button's dependencies) - The class sets a few custom properties and methods
- 类的名称是
mynamespace.Button
- 该类可以通过引用全局变量
mynamespace.Button
或者加载模型得到返回值使用 - 该类集成了dijit/from/Button类(所以代码片段引用了button模块)
- 该类自定义了一些属性和函数
Let's dig deeper into class creation with Dojo by learning about the constructor
method.
让我们更深入的了解一下类的定义,下面我们看下构造函数:
The constructor Method 构造函数
One of the special class methods is the constructor
method. The constructor
method is fired upon class instantiation, executed in the scope of the new object. This means that the this
keyword references the instance, not the original class. The constructor
method also accepts any number of instance-specific arguments.
类中的一个特殊的函数就是构造函数了。当一个类被实例化成一个兑现之后,构造函数就会被触发。这也就意味着,this关键字引用的是该实例,而不是原始的类。构造函数可以接受任意数量的参数。
// Create a new class
var Twitter = declare(null, {
// The default username
username: "defaultUser", // The constructor
constructor: function(args){
declare.safeMixin(this,args);
}
});
Take the following instance creation:
初始化类,得到一个实例:
var myInstance = new Twitter();
The username used within this instance will be "defaultUser" since no specific settings were provided to the instance. To leverage the safeMixin
method, provide a username parameter:
在没有做任何设置之前,实例中的username属性值为类中定义的默认值defaultUser。利用safeMixin
函数,设置一个名为username的参数:
var myInstance = new Twitter({
username: "sitepen"
});
Now the instance uses sitepen
as the username setting!
现在该实例的username属性值已经变为sitepen
了。
constructor: function(args){
declare.safeMixin(this,args);
该代码定义,就表明了该构造函数接受属性集合。declare.safeMixin
is also useful in class creation and inheritance. As the API docs state:
declare.safeMixin
在类的创建和继承中都十分有用,如API文档中描述:
This function is used to mix in properties like lang._mixin does, but it skips a constructor property and decorates functions like dojo/_base/declare does. It is meant to be used with classes and objects produced with dojo/_base/declare. Functions mixed in with declare.safeMixin can use this.inherited() like normal methods. This function is used to implement extend() method of a constructor produced with declare().
declare.safeMixin
is the perfect ally when creating classes with numerous options。
Inheritance 继承
As stated above, inheritance is defined within the second argument of declare
. Classes are mixed-in from left to right with each subsequent class' properties and methods getting priority over the previous if a property has already been defined. Take the following:
如上所述,我们在declare的第二个参数中定义继承的类。如果一个函数已经被定义,而继承的类中也定义了该函数,那么该数据将会被覆盖,从左到右依次覆盖。
// Define class A
var A = declare(null, {
// A few properties...
propertyA: "Yes",
propertyB: 2
}); // Define class B
var B = declare(A, {
// A few properties...
propertyA: "Maybe",
propertyB: 1,
propertyC: true
}); // Define class C
var C = declare([mynamespace.A, mynamespace.B], {
// A few properties...
propertyA: "No",
propertyB: 99,
propertyD: false
});
The result of the inherited class properties is:
继承后的类实例化的对象的属性值如下:
// Create an instance
var instance = new C(); // instance.propertyA = "No" // overridden by B, then by C
// instance.propertyB = 99 // overridden by B, then by C
// instance.propertyC = true // kept from B
// instance.propertyD = false // created by C
It is important to have a clear understanding of prototypical inheritance. When a property is read from an object instance, the instance itself is first inspected to see if the property is defined on it. If not, the prototype chain is traversed and the value from the first object in the chain that has the property defined is returned. When a value is assigned to a property it is always on the object instance, never the prototype. The result of this is that all objects that share a common prototype will return the same value for a property defined on the prototype, unless the value has been set on the instance. This makes it easy to define default values for primitive data types (number, string, boolean) in your class declaration and update them on instance objects as needed. However, if you assign object values (Object, Array) to a property on the prototype, every instance will manipulate the same shared value. Consider the following:
有一点很重要,就是理解原型继承。当我们从一个对象实例上读取属性信息时,实例会先检查自己本身有没有定义该属性。如果没有,则会遍历原型链,直到找到第一个定义该属性的对象未知,并返回。当把一个值赋值给对象时,总是会把该值赋值给对象本身,而不是原型。这样的好处时,所有实例在初始化的时候都共享同一个原型对象,并得到同样的值,除非在对象本身定义了该属性。所以我们可以在原始类中定义一些默认值(字符串、数字和bool),当需要修改的时候,再在对象中修改。但如果类中定义属性是对象或数字,那么实例化的类将操作的是同一个对象。看下如下代码:
var MyClass = declare(null, {
primitiveVal: 5,
objectVal: [1, 2, 3]
}); var obj1 = new MyClass();
var obj2 = new MyClass(); // both return the same value from the prototype
obj1.primitiveVal === 5; // true
obj2.primitiveVal === 5; // true // obj2 gets its own property (prototype remains unchanged)
obj2.primitiveVal = 10; // obj1 still gets its value from the prototype
obj1.primitiveVal === 5; // true
obj2.primitiveVal === 10; // true // both point to the array on the prototype,
// neither instance has its own array at this point
obj1.objectVal === obj2.objectVal; // true // obj2 manipulates the prototype's array
obj2.objectVal.push(4);
// obj2's manipulation is reflected in obj1 since the array
// is shared by all instances from the prototype
obj1.objectVal.length === 4; // true
obj1.objectVal[3] === 4; // true // only assignment of the property itself (not manipulation of object
// properties) creates an instance-specific property
obj2.objectVal = [];
obj1.objectVal === obj2.objectVal; // false
To avoid inadvertently sharing arrays or objects among all instances, object properties should be declared with null values and initialized in the constructor function:
为了避免上述情况发生,即多个实例对象共享一个属性对象或数组,我们需要在属性初始化的时候置空,在构造函数中初始化这些属性。
declare(null, {
// not strictly necessary, but good practice
// for readability to declare all properties
memberList: null,
roomMap: null, constructor: function () {
// initializing these properties with values in the constructor
// ensures that they ready for use by other methods
// (and are not null or undefined)
this.memberList = [];
this.roomMap = {};
}
});
Refer to the dojo/_base/declare documentation for additional information.
this.inherited
While completely overriding methods is certainly useful, sometimes the constructor of each class up through the inheritance chain should be executed to preserve its original functionality. This is where the this.inherited(arguments)
statement comes in handy. The this.inherited(arguments)
statement calls the parent class' method of the same name. Consider the following:
虽然自动的覆盖同名属性或函数是很有用的,但有些时候,在函数中,需要调用父类的一些原本的函数。此时,就可以使用this.inherited(arguments)
函数,该函数可以调用父类中同样名称的函数,代码如下:
// Define class A
var A = declare(null, {
myMethod: function(){
console.log("Hello!");
}
}); // Define class B
var B = declare(A, {
myMethod: function(){
// Call A's myMethod
this.inherited(arguments); // arguments provided to A's myMethod
console.log("World!");
}
}); // Create an instance of B
var myB = new B();
myB.myMethod(); // Would output:
// Hello!
// World!
The this.inherited
method can be called at any time within the child class' code. There will be some cases where you will want to call inherited()
in the middle of the child function, or even at the end. That said, you should not call it from within the constructor.
The this.inherited
函数可以在子类中任何地方调用。
Conclusion
The declare
function is the key to creating modular, reusable classes with the Dojo Toolkit. declare
allows for complex class recreation with multiple inheritance and any number of properties and methods. Better yet is that declare
is simple to learn and will allow developers to avoid repeating code.
dojo/_base/declare Resources
Looking for more detail about declare
and class creation? Check out these great resources:
Creating Classes 创建类的更多相关文章
- iOS Developer Libray (中文版)-- Defining Classes 定义类
该篇是我自己学习iOS开发时阅读文档时随手记下的翻译,有些地方不是很准确,但是意思还是对的,毕竟我英语也不是很好,很多句子无法做到准确的字词翻译,大家可以当做参考,有错误欢迎指出,以后我会尽力翻译的更 ...
- 使用StarUML创建类图
使用StarUML创建类图 http://www.flyne.org/article/379 1.综述(What) StarUML是一种生成类图和其他类型的UML图表的工具.本文是一个使用StarUM ...
- 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法
1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...
- MinkowskiEngine Miscellaneous Classes杂类
Miscellaneous Classes杂类 内核生成器 class MinkowskiEngine.KernelGenerator(kernel_size = -1,stride = 1,dila ...
- 设计模式之创建类模式大PK
创建类模式大PK 创建类模式包括工厂方法模式.建造者模式.抽象工厂模式.单例模式和原型模式,他们能够提供对象的创建和管理职责.其 ...
- 自己动手之使用反射和泛型,动态读取XML创建类实例并赋值
前言: 最近小匹夫参与的游戏项目到了需要读取数据的阶段了,那么觉得自己业余时间也该实践下数据相关的内容.那么从哪入手呢?因为用的是Unity3d的游戏引擎,思来想去就选择了C#读取XML文件这个小功能 ...
- ios动态创建类Class
[Objective-C Runtime动态加载]---动态创建类Class 动态创建类Class,动态添加Class成员变量与成员函数,动态变量赋值与取值,动态函数调用等方法 a.使用objc_al ...
- python动态创建类的声明
动态创建类的声明 使用内置函数type,原型:class type(name, bases, dict)name是类的名字,相当于__class__bases是类的基类,元组,可以有多个基类,但是基类 ...
- C# 利用反射根据类名创建类的实例对象
“反射”其实就是利用程序集的元数据信息. 反射可以有很多方法,编写程序时请先导入 System.Reflection 命名空间. 1.假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型): ...
随机推荐
- thoughtworks编程题
微博看到vczh分享的thoughtworks的一道题目https://www.jinshuju.net/f/EGQL3D,代码写完之后才得知这个公司并不是我想的那样美好. 题目: FizzBuzzW ...
- Mac小知识(不定时更新)
1.显示隐藏文件夹(在mac命令行中输入以下代码即可): 1)显示隐藏文件夹 defaults write com.apple.finder AppleShowAllFiles Yes &&a ...
- 机器学习之分类器性能指标之ROC曲线、AUC值
分类器性能指标之ROC曲线.AUC值 一 roc曲线 1.roc曲线:接收者操作特征(receiveroperating characteristic),roc曲线上每个点反映着对同一信号刺激的感受性 ...
- php判断json对象是否存在的方法
在实际测试中php读取json数组时 使用简单的 if 或者 array_key_exists 去判断对象是否存在是会报错的,以下是google搜寻的正确判断方法 实际上出现报错只是我对php还不是很 ...
- 蓝牙-HCI错误码列表
错误码定义: /* Success code */ #define HCI_SUCCESS 0x00 /* Possible error codes */ #define HCI_UNKNOWN_HC ...
- eclipse 配置c++
安装mingw一直安装不成功 用TDM-GCC方便多了 附链接http://tdm-gcc.tdragon.net/
- node.js Websocket实现扫码二维码登录---GoEasy
最近在做一个扫码登录功能,为此我还在网上搜了一下关于微信的扫描登录的实现方式.当这个功能完成了后,我决定将整个实现思路整理出来,方便自己以后查看也方便其他有类似需求的程序猿些. 要实现扫码登录我们需要 ...
- 详解SVN 的使用
一.什么是SVN SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. 二.SVN的下载安装 下载地址:http ...
- java中常见的几种Runtimeexception
转自http://blog.csdn.net/qq635785620/article/details/7781026 一般面试中java Exception(runtimeException )是必会 ...
- Python实例1
1.有1.2.3.4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 错解: 正解: 源码: #!/usr/bin/python for i in range(1,5): for j in ...