定义和使用类
ST 2是面向对象的语言,在开发过程中当然要创建(定义)和使用类。本文简介了ST2的类系统。如果你想以面向对象的角度理解ST2,那么这篇文章应该是非常有意义的!!
本文整理自http://www.cnblogs.com/html5mob/archive/2012/07/14/2591463.html ,感谢作者精彩的文章。
ST中有强大的类系统定义模型,可以很轻松的创建和使用javascript类。
ST中大家用到的东西都已封装成类,如:组件/容器,事件模型,数据模型,数据存储,控制器......等等!
类
用Ext.define来定义一个类
//声明一个动物类 Ext.define('Animal'); //可以这样实例化这个类 Var kiti = Ext.create('Animal');
这是ST2中定义类的语法,这个类只有一个类名,没有字段、属性、方法、构造方法。
字段
Ext.define('Animal'{ //字段 name:null, age:null }); var kiti = Ext.create('Animal'); //这样初始化字段 Kiti.age = 12; //这样访问字段 Var age = kiti.age;
这个类中定义了两个字段
这样访问字段:
animal.name
属性
//声明一个动物类 Ext.define('Animal', { //字段 age:null, //属性 config: { name:null, }); var kiti = Ext.create('Animal'); //这样初始化属性(使用setter访问器) kiti.setName('kiti'); //这样访问属性(使用getter访问器) Var name = kiti.getName();
这个 Animal 类定义了一个 age 字段,一个 name 属性。这样访问属性:
Setter 和 getter 访问器
Var name = kiti.getName();
Getter 和 setter方法是矿建自动生成的,可以直接调用。
构造方法
//声明一个动物类
Ext.define('Animal', {
//字段
age:null,
//属性
config:
{
name:null,
},
//构造器(空造函数)
constructor: function() {
},
});
//针对这个构造器,这样实例化此类
var kiti = Ext.create('Animal');
Kiti.age = 12;
kiti.setName('kiti');
这个类定义了一个age字段,一个name属性,一个空的构造方法。
构造方法有很多种写法,比如:
//字段和属性的定义省略 //构造器 constructor: function(age,name) { //字段进行初始化 this.age=age; //属性进行初始化 this.setName(name); } //针对这个构造器,这样实例化此类 var kiti = Ext.create('Animal','12','kiti');
再比如:
//字段和属性的定义省略 //构造器 constructor: function(config) { this.initConfig(config); } //针对这个构造器,这样实例化此类 var kiti = Ext.create('Animal',{name:'kiti'});
再比如:
//字段和属性的定义省略 //构造器 constructor: function(age,config) { this.age = age; this.initConfig(config); } //针对这个构造器,这样实例化此类 var kiti = Ext.create('Animal','12',{name:'kiti'});
方法从上面的代码可以看出来ST2的类系统是非常灵活的。几乎和java一样。
//声明一个动物类 Ext.define('Animal', { //字段 age:null, //属性 config: { name:null, }, //构造器(空造函数) constructor: function() { }, }); //定义方法 sayHello:function(){ Console.log('你好,我的名字叫'+this.getName()+'我今年'+this.age+'岁了'); }
属性和字段
到这里,使用者需要去确认哪些是类字段,哪些是属性,才能使用他们。那就意味着:使用者都需要看你的类描述才能进行构造它,创建它,防止构造的时候传错参数。
ST提倡一种标准的方法使用属性,实例化时只使用属性,而不使用字段。
属性控制
在现实开发中,一些属性字段,可能会有一些业务或者边界上的检查,比如年龄这样的属性,如果这个动物是狗你给来个1000岁,那都成精了是不?
所在以赋值的时候就必须进行检查。
看看代码我们是如何做到属性控制的呢?
Ext.define('Animal', { config: { name:null, age:null, }, constructor: function(config) { this.initConfig(config); }, sayName: function() { console.log("hello 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, applyName:function(name) { //在此如果我们没有任何检查可以直接返回name,但我们需要做名字的检查,如果名字是王八蛋 //那么就必须反抗,否则才接受 if(name=="王八蛋") { console.log('你太不厚道了,不能给我取这样的名字'); } else { return name; } } }); var animal=new Animal({name:"小黑",age:5}); animal.sayName(); animal.setName("王八蛋"); console.log(animal.getName()); animal.setName("大黑"); console.log(animal.getName());
我们F12看看控制台输出的结果:
hello 我的名字叫:小黑 我今年:5岁!
你太不厚道了,不能给我取这样的名字
小黑
大黑
可以看出,当我们给它改名为王八蛋的时候,它反抗了,名字没有改成功。后面我们让它叫大黑,它就接受了!
继承
ST里面继承可通过extend关键字实现
//声明一只狗 Ext.define('Dog', { //狗中从动物继承 extend:'Animal', //属性 config: { name:null, age:null, }, constructor:function(config) { this.initConfig(config); }, sayName:function() { alert("超级狗 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, bark:function() { alert("狗叫了"); } });
上述代码,添加了一个bark方法和复写了sayName方法
依赖与动态加载
大多数时候,类之间都存在着依赖。我们可以使用"requires"关键字来引入一个被依赖的类。人类依赖动物类并扩展动物类,这种情况下并不需要特殊的说明,用"extend"就已经表明了这种依赖关系。
Ext.define('Human', { extend:'Animal', requires:'Ext.MessageBox', speak:function() { Ext.Msg.alert() } });
当你像这样定义一个类的时候,ST就会检查并异步加载Ext.MessageBox。
Ext.MessageBox也可能依赖于其他类,这些类也将在后台自动加载。Ext.MessageBox和动物类都加载完毕后,就会定义人类。然后就可以使用Ext.create实例化"人"了。
在开发过程中,多文件可以让我们有效地管理代码,但应用发布后,应该尽量减少文件的数目以提高网络响应速度。ST2的JSBuilder工具可以分析你的应用程序,并将你所有代码连同你所用到的ST中的类合并成一个js文件。关于JSBuilder使用方法的介绍,请看ST参考文档的第二部分。
命名空间和类的别名
类似于java中的包的概念,为了解决类重名问题。类的别名是为了好记。(另外,使用别名实例化类和常规方式实例化类是不同的,在此不在叙述)
//声明一个动物类【名称空间为Deom】 Ext.define('Demo.Animal', { //创建动物类的别名 alias:'widget.animal', //声明一只狗【名称空间为Demo】 Ext.define('Demo.Dog', { //狗中从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias:'widget.dog', }); //我们通过类全名(带上名称空间)创建类 var dog=new Demo.Dog(); dog.bark(); //我们通过别名创建类 var dog1=Ext.widget('dog'); //var dog2 = {xtype:'dog'};这样也是可以的,但是这样实例化的变量时不能调用方法的。具体在看文档,这一点不能确定。 dog1.bark(); //我们通过ST的通用静态方法创建类[创是需要类的全路径] var dog2=Ext.create("Demo.Dog"); dog2.bark();
____________________________________________________________________________________________________
附件:ST的命名约定
使用统一的风格来命名类、名空间和文件名有助于更好地组织代码,保证代码的条理性和可读性。
1) 类
类名只能由字符和数字组成。不要在类名中出现数字,除非它属于一个技术术语。不要使用下划线,连字符,以及任何字母数字以外的字符。例如:
MyCompany.useful_util.Debug_Toolbar 不要这样写
MyCompany.util.Base64 这个OK
每个类都要有命名空间。用"."来为类分配命名空间,把类分配到不同的包内。例如:
MyCompany.data.CoolProxy
MyCompany.Application
顶级的命名空间和类名使用骆驼拼写法,其他的都用小写。例如:
MyCompany.form.action.AutoLoad
非框架本身的类,不要使用Ext作为顶级命名空间。
首字母缩略词也应该遵循上面列出的骆驼拼写法约定。例如:
使用 Ext.data.JsonProxy 而不用 Ext.data.JSONProxy
使用 MyCompany.util.HtmlParser 而不用 MyCompary.parser.HTMLParser
使用 MyCompany.server.Http 而不用 MyCompany.server.HTTP
2) 源文件
类名直接映射到类文件的存储路径。因此,每个文件对应一个类(就像java一样)例如:
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 是你存储脚本的目录(译者注:这里不是真的"path/to"而是你的app目录),所有的类都应该保存在这个目录下,并被正确地划分命名空间。这样Ext .require()方法才能正确地动态载入脚本文件。这样对将来的维护和部署工作都也很会有帮助。
3) 变量和方法
跟类名一样, 变量名和方法名只能由字符和数字组成。不要在类名中出现数字,除非它属于一个技术术语。不要使用下划线,连字符,以及任何字母数字以外的字符。
变量名和方法名应该使用首字母小写的骆驼拼写法。示例:
好的方法名: getHtml() getJsonResponse() parseXmlContent()
不好的方法名:getHTML() getJSONResponse() parseXMLContent()
好的变量名:isGoodName base64Encoder xmlReader httpServer
4) 属性
除静态属性以外的类的属性,其命名方式跟方法和变量的一样。
静态属性全部用大写命名,例如:
Ext.MessageBox.YES = "Yes"
Ext.MessageBox.NO = "No"
MyCompany.alien.Math.PI = "4.13"