ExtJS5拥有许许多多的类,到目前为止使用ExtJS开发的人员有200多万,他们来自不同的地域,拥有不同的背景。所以这样说来,在如下这些代码结构上提供一份公共代码结构上我们就面临着一个巨大的挑战:
1.大家都了解和熟悉,并且简单和容易学习
2.开发迅速,调试方便,部署的时候也没有痛苦
3.组织性强,可扩展性强,可维护性强
JavaScript是面向原型类的语言,其最强大的特性就是自由,解决不同的问题可以有好多的解决方案,并且可以使用不同的编码风格和技术,代价就是这样就会有很多不确定性发生。如果缺乏一个统一的结构,javascript代码就很难理解、难维护和复用。
另一方面,基于类的编程仍然是最流行的面向对象的编程模式,基于类的语言通常需要强类型,封装和标准的编码惯例,通过让开发人员坚持大量的规则,让代码更具有可预测性,可扩展和可伸缩性。然而,这样就损失了JavaScript的动态特性。
每个方法都有优点和缺点,那我们是否可以保持好的而同时隐藏坏的部分?答案是肯定的,ExtJS就是这样一个解决方案。
命名约定
在代码中对名称进行统一规约,如基础类、名称空间和文件名,可以让你的代码在结构化和可读性上更方便组织管理。
类命名约定
类名只能包含字母数字字符。数字被允许但是不被鼓励,除非他们属于一个技术术语。不要使用下划线、连字符或其他任何非字母数字字符。例如: MyCompany.useful_util.Debug_Toolbar 带有下划线,所以不是合法的,MyCompany.util.Base64是可以的。
类名应该以适当的名称空间,并且以对象属性(.)进行分组归类。类名至少应该有一个独特的顶级名称空间中紧随其后。例如:MyCompany.data.CoolProxy MyCompany.Application
顶级名称空间和实际的类名应该采取驼峰模式,其它的则应该都小写,例如: MyCompany.form.action.AutoLoad
不是sencha生成的类尽量不要使用Ext作为顶级空间。缩略词也应该遵守驼峰预约定,如:
使用Ext.data.JsonProxy 而不是Ext.data.JSONProxy
使用 MyCompany.util.HtmlParser 而不是MyCompary.parser.HTMLParser
使用MyCompany.server.Http 而不是MyCompany.server.HTTP
源文件命名约定
类的名称直接映射到它们存储的文件路径。因此,必须只有一个类文件。例如:
Ext.util.Observable 是在如下目录存储的path/to/src/Ext/util/Observable.js
Ext.form.action.Submit 是在如下目录存储的path/to/src/Ext/form/action/Submit.js
MyCompany.chart.axis.Numeric是在如下目录存储的path/to/src/MyCompany/chart/axis/Numeric.js
path/to/src源码路径 是你的应用程序类的目录,所有类都应该在本根目录下,并且为了方便开发、维护和部署体验,都应该进行适当的命名规约。
方法和变量的命名规则
以类似类名的方式,方法名和变量名只能包含字母,数字被允许但是不被鼓励使用,除非他们属于一个技术术语。不要使用下划线、连字符或其他任何非字母数字字符。方法和变量名应该遵循驼峰原则这也适用于缩略词。
例如:
可接受的方法名称:
encodeUsingMd5()
getHtml()而不是getHTML()
getJsonResponse()而不是getJsonResponse()
parseXmlContent()而不是parseXMLContent()
可接受的变量名:
varisGoodName
varbase64Encoder
varxmlReader
varhttpServer
属性的命名规则
类属性名遵循完全相同的约定,但静态常量除外。静态类常量属性应该全部大写。例如:
Ext.MessageBox.YES= "Yes"
Ext.MessageBox.NO = "No"
MyCompany.alien.Math.PI = "4.13"
声明
你可能使用一个方法就可以完成一个类的声明:Ext.define。它最基本的语法就如:Ext.define(className,members, onClassCreated);
className:类名
members:一个对象,代表一个类成员的键-值对的集合
onClassCreated:一个可选的回调函数当,当它所依赖的类和类本身创建完成时被调用。由于类创建的异步本性,这个回调在很多情况下是非常有用的,这些将在第四部分进一步讨论。
例子:
Ext.define('My.sample.Person',{//注释 使用Ext.define进行类的定义 定义类名为Person 存储在My/sample文件夹下
name: 'Unknown',
constructor: function(name) {//构造函数
if (name) {
this.name = name;
}
},
eat: function(foodType) {//对象方法
alert(this.name + " is eating:" + foodType);
}
});
//创建和使用的例子
varbob = Ext.create('My.sample.Person', 'Bob');
bob.eat("Salad");// alert("Bob is eating: Salad");
注意:我们创建了一个新的My.sample的实例时使用了Ext.create()方法,我们也可以使用新的关键字new(new
My.sample.Person())。不过建议要养成总是使用Ext.create的习惯,因为这样您就开启了动态加载,动态加载的更多信息参见入门指南,动态加载可以节省对象创建,提升效率节省空间。
配置
同样,也有一个专用的属性会在强大的Ext类创建之前进行预处理:config,它包含如下特性:
1.与其他类成员配置是完全隔离的
2.如果getter和setter方法还未显示定义,原生类会在创建期间为每个对象属性自动生成。
3.自动生成的setter方法会内部调用apply方法(如果类中有定义)。如果你需要运行自定义逻辑来处理预先设置的值,你可以覆写apply方法申请配置属性,。如果apply不返回一个值,setter不会设置值。当不同的值被设置时update更新方法也会被调用,apply和update方法有old
value和new value作为参数。
对使用Ext configs的类,不再需要手动调用initConfig()。但是,对于扩展于Ext.Base的自己的类,
initConfig()方法仍然需要手动调用。
可以看到下面的配置示例:
Ext.define('My.own.Window', {
extend: 'Ext.Component',
/** @readonly */
isWindow: true,
config: {
title: 'Title Here',
bottomBar: {
height: 50,
resizable: false
}
},
applyTitle: function(title) {
if (!Ext.isString(title) || title.length === 0) {
alert('Error: Title must be a validnon-empty string');
}
else {
return title;
}
},
applyBottomBar: function(bottomBar) {
if (bottomBar) {
if (!this.bottomBar) {
returnExt.create('My.own.WindowBottomBar', bottomBar);
}
else {
this.bottomBar.setConfig(bottomBar);
}
}
}
});
/** A child component to complete the example.*/
Ext.define('My.own.WindowBottomBar', {
config: {
height: undefined,
resizable: true
}
});
下面是一个如何使用它的例子:
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 });
alert(myWindow.getBottomBar().getHeight());// alerts 100
静态变量
静态变量可以使用statics配置来定义:
Ext.define('Computer', {
statics: {
instanceCount: 0,
factory: function(brand) {
// 'this' in static methods referto the class itself
return new this({brand: brand});
}
},
config: {
brand: null
}
});
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"
错误控制和调试
Ext JS包括一些有用的特性,将帮助您调试和错误处理。
您可以使用Ext.getDisplayName()来获取任何方法的显示名称。这对抛出错误的类名和方法名描述来说是特别有用的:
throw new Error('['+Ext.getDisplayName(arguments.callee) +'] Some message here');
当有错误在使用Ext.define时抛出的时候,你应该查看这个方法还有类的堆栈信息,你可以看下谷歌Chrome中报错的信息如下: