概览
Extjs4对新的类系统进行了大量的比较彻底的重构,新的架构建立在写在Extjs4库中每一个单独的类,在开始进行extjs4编码前最好对类系统有一定了解。
首先,类系统概览讲说明为什么需要一个完整的类系统,主要就是说Extjs库包含的类很多,开发人员来自世界各处,编程背景不同,因此需一个通用的代码架构去解决这些问题,而这样的架构包含如下特点:易学,易用,易开发,易部署,很好的组织,扩展以及维护性。
js语言是没有类的,面向原型的语言。因此js最大的特点是灵活。可以在不通的编码风格及技术条件下,通过不同方式达到同样的效果,这样同事带来花费的不可预见性,没有统一的结构,js代码很难被理解,管理以及重用。
基于类的编程,换句话说,就是面向对象的编程模型,基于类的语言通常需要强类型,提供封装特性,并有标注的编码规范,一般通过使开发人员遵循大量原则,使得编码很容易预测,扩展,以及缩短时间,但是相对js,这些语言失去了灵活性。
js以及其它面向对象的语言各有好处,Extjs在这方面有了很好的解决方案。
命名规范
在你编码过程中对类,名字空间以及文件名使用统一的命名规则对你代码的组织,结构化以及可读性有很大的好处。
类命名规范
类名最好只包含字母,在多数情况下,数字是不鼓励使用的,除非非要用不可,也不要使用下划线,-以及其它非字母字符,例子如下:
MyCompany.useful_util.Debug_Toolbar 不鼓励这样命名
MyCompany.util.Base64 可接受的命名
类名最好包组织,在适当的名字空间通过使用.来访问对象属性,至少,类名应该有一个顶层的包。例如
MyCompany.data.CoolProxy
MyCompany.Application
顶层的包名以及实际的类名应该使用CamelCased命名规范,其它应该为小写,如下:MyCompany.form.action.AutoLoad
不要使用Ext作为顶层包名,首字母应该遵循CamelCased命名规范,如
Ext.data.JsonProxy instead of Ext.data.JSONProxy
MyCompany.util.HtmlParser instead of MyCompary.parser.HTMLParser
MyCompany.server.Http instead of MyCompany.server.HTTP
源文件命名规范
类名直接映射到存储该类的文件路径,因此,每个文件只能有一个类,如
Ext.util.Observable is stored in path/to/src/Ext/util/Observable.js
Ext.form.action.Submit is stored in path/to/src/Ext/form/action/Submit.js
MyCompany.chart.axis.Numeric is stored in path/to/src/MyCompany/chart/axis/Numeric.js
path/to/src目录包含应用的所有类,所有类应该放在这个公共根目录下,以合适的名字空间来获得最好的开发,管理以及部署体验。
方法以及变量的命名规则与类命名相似,方法和变量的命名也只包含字母,数字不鼓励使用,除非必须用到,同样不使用下划线,-以及其它非字母字符。
方法和变量命名应该遵循CamelCased命名规范,应适用首字母。例如
可接受的方法名:
encodeUsingMd5() ,用getHtml() 替代 getHTML() 用getJsonResponse()替代 getJSONResponse(),用 parseXmlContent()替代parseXMLContent()
可接受的变量名:
var isGoodName var base64Encoder var xmlReader var httpServer
属性命名
类属性命名和上面方法以及变量一样,除了当属性是静态常量的时候。
当属性是静态常量时,字母应该大写。
Ext.MessageBox.YES = "Yes"
Ext.MessageBox.NO = "No"
MyCompany.alien.Math.PI = "4.13"
实践
1.声明
在extjs4之前,使用Ext.extend创建类
var MyWindow = Ext.extend(Object, { ... });
这种方式很容易从一个父类中创建一个新类,除了直接继承功能,开发人员没有一个可以和关于创建类的其它方面有关的API,比如配置,静态,聚合等,下面是对这些特点的简短细节回顾。
另一个例子
:My.cool.Window = Ext.extend(Ext.Window, { ... });这里使用了名字空间,使得新类从Ext.Window中继承。
两个需要关注的地方:
A.My.cool在指定Window作为它的属性前必须有一个存在的对象
B.Ext.Window在它被引用必须在页面中存在或已被加载
A通常通过Ext.namespace(别名为Ext.ns)来解决,该方法会递归对象/属性树,如果当前还不存在就会创建。烦人的是你在任何时候你都要在Ext.extend前加上他们。
B不是很容易去解决,因为Ext.Window可能依赖很多其它直接或间接继承的类,反过来,这些依赖的类可能会依赖其它类存在,这些导致了在extjs4之前开发应用程序通常需要包含整个extjs库即使在程序中只用到extjs很小的一部分。
新的方式
Extjs4通过一个开发人员需要在创建类时皆著的方法-Ext.define解决了上述的所有缺点。它的基本语法如下
Ext.define(className, members, onClassCreated);
className:类名
members:这是一个对象,它表示一个以键值对形式表示的类成员集合。
onClassCreated:这是一个可定制的回调函数,当这个类所依赖的类都准备完毕时便会调用这个回调函数,并且类本身将会完全创建。由于有这个类创建新异步属性,这个回调在很多情况都会很有用。以下是一个例子
Ext.define('My.sample.Person', {
name: 'Unknown',
constructor: function(name) {
if (name) {
this.name = name;
}
},
eat: function(foodType) {
alert(this.name + " is eating: " + foodType);
}
});
var aaron = Ext.create('My.sample.Person', 'Aaron');
aaron.eat("Salad"); // alert("Aaron is eating: Salad");
上面用Ext.cteate()方法创建了类My.sample.Person的实例。可以使用new关键字(new My.sample.Person())。但是习惯是总是使用Ext.create因为它在动态加载上有优势。有关动态加载在Extjs-start中有提到。
配置
在ExtJS4中将介绍一个专业的配置属性,配置属性在类被创建前会被强大的Ext.Class预处理程序所处理,其特性如下:
A.
Configurations:
配置属性对于其它类成员是被完全封装的
B.
Getter and setter:在创建类的过程,如果这个类还没有定义getter和setter方法,就会类原型中为每个配置属性自动生成getter和setter方法。
C.apply:Apply方法也能为每个配置属性生成setter和getter方法,在设置属性值前,调用内置的apply方法自动生成setter方法。如果在设置属性值前需要定制逻辑可以通过为配置属性覆盖apply方法。如果app方法没有返回一个值,那么setter将不会设置值,例子如下
Ext.define('My.own.Window', {
/** @readonly */
isWindow: true,
config: {
title: 'Title Here',
bottomBar: {
enabled: true,
height: 50,
resizable: false
}
},
constructor: function(config) {
this.initConfig(config);
},
applyTitle: function(title) {
if (!Ext.isString(title) || title.length === 0) {
alert('Error: Title must be a valid non-empty string');
}
else {
return title;
}
},
applyBottomBar: function(bottomBar) {
if (bottomBar && bottomBar.enabled) {
if (!this.bottomBar) {
return Ext.create('My.own.WindowBottomBar', bottomBar);
}
else {
this.bottomBar.setConfig(bottomBar);
}
}
}
});
var myWindow = Ext.create('My.own.Window', {
title: 'Hello World',
bottomBar: {
height: 60
}
});
alert(myWindow.getTitle()); // alerts "Hello World"
myWindow.setTitle('Something New');
alert(myWindow.getTitle()); // alerts "Something New"
myWindow.setTitle(null); // alerts "Error: Title must be a valid non-empty string"
myWindow.setBottomBar({ height: 100 }); // Bottom bar's height is changed to 100
静态
静态成员通过staitcs配置定义
Ext.define('Computer', {
statics: {
instanceCount: 0,
factory: function(brand) {
// 'this' in static methods refer to the class itself
return new this({brand: brand});
}
},
config: {
brand: null
},
constructor: function(config) {
this.initConfig(config);
// the 'self' property of an instance refers to its class
this.self.instanceCount ++;
}
});
var dellComputer = Computer.factory('Dell');
var appleComputer = Computer.factory('Mac');
alert(appleComputer.getBrand()); // using the auto-generated getter to get the value of a config property. Alerts "Mac"
alert(Computer.instanceCount); // Alerts "2"
错误处理与调试
ExtJS4包含了一些有用的特性可以帮助你调试和错误处理
A.你能使用Ext.getDisplayName()方法去获取任何方法的显示名,这对于抛出包含类名和方法名描述的错误特别有用。
throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');
B.当使用Ext.define()方法定义的任何类中的任何方法有错误抛出,如果使用chrom,开发人员将在调用栈中看到类名和方法名。