Sencha touch 开发系列:类系统
类是啥玩意呢?我想玩过面象对象语言的人,对它一点也不会陌生了。
我还是重申下这玩意吧
类是对象概念在面向对象编程语言中的反映,是相同对象的集合,类描述了一系列在概念上有相同的含义的对象,并为这些对象同一定义了编程语言上的属性和方法。例如:动物是一个类,狗、鸡、猪也是类。但是他们的具体的属性和方法可能不完全相同。
ST中有强大的类系统定义模型,可以很轻松的创建javascript类。
ST中大家用到的东西都已封装成类,如:组件/容器,事件模型,数据模型,数据存储,控制器......等等!
下面我们就来讲讲,如何定义类?
其实,你在学习组件,的时候已经用到了!
用Ext.define来声明一个类
//声明一个动物类 Ext.define('Animal', { //字段 name: null, age:null, constructor: function(name,age) { //构造中给字段复制 this.name=name; this.age=age; }, //说hello方法 sayName: function() { alert("hello 我的名字叫:"+this.name+",我今年:"+this.age+"岁!"); } }); //创建一个动物类的实例(产生一个动物) var animal=new Animal("小黑",5); //动物介绍自己 animal.sayName();
动运行,会打印出 hello 我的名字叫小黑,我今年:5岁!
很简单吧,和C#,java这类语言类似了是不?
当我们要访问类字段的时候,也很简单如:
animal.name
你也可以给字段复值
animal.name="王八蛋"
有同学会问了,有没有像我们C#,java中属性的概念呢?
就是通过get,set访问和设置器进行操作呢
那在ST里面如何做到呢?ST也确实为我们提供了一个这样的机制。
看代码:
//声明一个动物类 Ext.define('Animal', { //字段 age:null, //属性 config: { name: null, }, //构造器 constructor: function(age,config) { //构造中给字段复制 this.age=age; //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("hello 我的名字叫:"+this.getName()+" 我今年:"+this.age+"岁!"); } }); //创建一个动物类的实例(产生一个动物) var animal=new Animal(5,{name:'小黑'}); //动物介绍自己 animal.sayName();
输出和上面的一样的了,只是我在这里做了下改动,把age定义为字段,把name定义为属性
注意看属性的定义及访问方式
属性必须放在config下面在构告函数中可调用initConfig进行统一属性配置。
也可以在外部通过调用get+"属性名[首字母大定]"或set+"属性名[首字母大定]"进行访问,配置。
下在我将上面例子改下。
//声明一个动物类 Ext.define('Animal', { //字段 age:null, //属性 config: { name: null, }, //构造器(空造函数) constructor: function() { }, //说hello方法 sayName: function() { alert("hello 我的名字叫:"+this.getName()+" 我今年:"+this.age+"岁!"); } }); //创建一个动物类的实例(产生一个动物) var animal=new Animal(); //访问字段进行年年龄设置 animal.age=5; //访问属性进行名字设置 animal.setName("小黑"); //动物介绍自己 animal.sayName();
看,输出还是一样。
再看一段:
//声明一个动物类 Ext.define('Animal', { //字段 age:null, //属性 config: { name: null, }, //构造器(空造函数) constructor: function(age,name) { //字段进行初始化 this.age=age; //属性进行初始化 this.setName(name); }, //说hello方法 sayName: function() { alert("hello 我的名字叫:"+this.getName()+" 我今年:"+this.age+"岁!"); } }); //创建一个动物类的实例(产生一个动物) var animal=new Animal(5,"小黑"); //动物介绍自己 animal.sayName();
输出仍然是一样的!
你看到没有,我们可以很方便,很灵活的创建使用类。
但你会发现,太灵活也悲催了,使用者需要去确认哪些是类字段,哪些是属性。
如果你定义了一个类,使用者都需要看你的类描述才能进行构造它,创建它,怕构造的时候传错。
ST提倡一种标准的声明法使用属性,使用者只需要在创建的时候传或不传config访问操作的时候一律使用get,set 访问器。
如;
//声明一个动物类 Ext.define('Animal', { //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("hello 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); } }); //创建一个动物类的实例(产生一个动物) var animal=new Animal({name:"小黑",age:5}); //动物介绍自己 animal.sayName();
输出还是一样,但规范了很多,至少创建者只需要关心config有哪些方法有哪些就好!
这时,那个叫王八蛋的动物发彪了,它抗议不通随便给叫这样的名字,必须禁止这样的情况出现?
确实,在现实开发中,一些属性字段,可能会有一些业务或者边界上的检查,比如年龄这样的属性,如果这个动物是狗你给来个1000岁,那都成精了是不?
所在以赋值的时候就必须进行检查。
看看代码我们是如何做到属性控制的呢?
//声明一个动物类 Ext.define('Animal', { //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 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看看控制台输出的结果:
下面继续玩玩ST类的特性:继承
ST里面继承可通过extend配置
如:
//声明一只狗 Ext.define('Dog', { //狗中从动物继承 extend:'Animal', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("超级狗 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //狗叫 bark:function() { alert("狗叫了"); } });
看代码备注,这个extend是不是很熟悉,我们写组件,view的时候都有用到!这里通过extend关键字,让动物类派生了一个具特的动物狗类(狗有很多品种,每个品种都有些不一样的地方,你可以让狗再派生出哈巴狗或啥的)
上述代码,添加了一个bark方法和复写了sayName方法
JS是一种弱类型语言,所以没有java,c#在类应用上这么直观。你只要慢慢习惯就好了.....
类的别名与类的名称空间及类的创建
//声明一个动物类【名称空间为Deom】 Ext.define('Demo.Animal', { //创建动物类的别名 alias: 'widget.animal', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { console.log("hello 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //在赋值名字前 applyName:function(name) { //在此如果我们没有任何检查可以直接返回name,但我们需要做名字的检查,如果名字是王八蛋 //那么就必须反抗,否则才接受 if(name=="王八蛋") { console.log('你太不厚道了,不能给我取这样的名字'); } else { return name; } } }); //声明一只狗【名称空间为Demo】 Ext.define('Demo.Dog', { //狗中从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.dog', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("超级狗 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //狗叫 bark:function() { alert("狗叫了"); } }); //我们通过类全名(带上名称空间)创建类 var dog=new Demo.Dog(); dog.bark(); //我们通过别名创建类 var dog1=Ext.widget('dog'); dog1.bark(); //我们通过ST的通用静态方法创建类[创是需要类的全路径] var dog2=Ext.create("Demo.Dog"); dog2.bark();
还是注意看代码备注了,类的名称空间:是为了解决类名冲突
类的别名:为了类使用更简单更好记
下面我们再讲下在类里面如何添加事件
ST为封装了很好的事件模型接口mixins: ['Ext.mixin.Observable']
我们能过扩展事件接口,就可以去点火事件了。
比下我们下面来为狗添加一个dogbark事件,当你调用bark方法的时候,会去执行dogbark事件
看代码:
//声明一个动物类【名称空间为Deom】 Ext.define('Demo.Animal', { //创建动物类的别名 alias: 'widget.animal', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { console.log("hello 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //在赋值名字前 applyName:function(name) { //在此如果我们没有任何检查可以直接返回name,但我们需要做名字的检查,如果名字是王八蛋 //那么就必须反抗,否则才接受 if(name=="王八蛋") { console.log('你太不厚道了,不能给我取这样的名字'); } else { return name; } } }); //声明一只狗【名称空间为Demo】 Ext.define('Demo.Dog', { //狗中从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.dog', //内联继承事件接口 mixins: ['Ext.mixin.Observable'], //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("超级狗 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //狗叫 bark:function() { console.log("狗叫了"); //触发狗叫事件 this.fireEvent("dogbark",this); } }); //我们通过ST的通用静态方法创建类[创是需要类的全路径] var dog=Ext.create("Demo.Dog"); //添加狗叫监听 dog.on("dogbark",function(e){ alert("狗真的叫了!"); }); //调用狗叫方法 dog.bark();
上面代码是alert出:狗真的叫了! 你可以试试!
然后你再看看代码,我们是如何添加事件的?
下面我们来一个综合点的例子:利用事件完成一个经典的设计模式:观察者模式
狗叫了:猫叫了,老鼠跑了,主人醒了!实现这个连动效果场景。
还是例用上面的代码!
//声明一个动物类【名称空间为Deom】 Ext.define('Demo.Animal', { //创建动物类的别名 alias: 'widget.animal', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { console.log("hello 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //在赋值名字前 applyName:function(name) { //在此如果我们没有任何检查可以直接返回name,但我们需要做名字的检查,如果名字是王八蛋 //那么就必须反抗,否则才接受 if(name=="王八蛋") { console.log('你太不厚道了,不能给我取这样的名字'); } else { return name; } } }); //声明一只狗【名称空间为Demo】 Ext.define('Demo.Dog', { //狗从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.dog', //内联继承事件接口 mixins: ['Ext.mixin.Observable'], //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //说hello方法 sayName: function() { alert("超级狗 我的名字叫:"+this.getName()+" 我今年:"+this.getAge()+"岁!"); }, //狗叫 bark:function() { console.log("狗叫了!"); //触发狗叫事件 this.fireEvent("dogbark",this); } }); //声明一只猫【名称空间为Demo】 Ext.define('Demo.Cat', { //猫也从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.cat', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //猫叫了 bark:function() { console.log("猫叫了!"); } }); //声明一只老鼠【名称空间为Demo】 Ext.define('Demo.Mice', { //老鼠也从动物继承 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.mice', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //老鼠跑路 run:function() { console.log("老鼠跑路了!"); } }); //声明一只主人【名称空间为Demo】 Ext.define('Demo.Human', { //人也从动物继承【传说人类也是动物】 extend:'Demo.Animal', //创建狗类的别名 alias: 'widget.human', //属性 config: { name: null, age:null, }, //构造器 constructor: function(config) { //初始化属性 this.initConfig(config); }, //主人醒了 wake:function() { console.log("主人醒了!"); } }); //这里动作的触发者是狗 var dog=Ext.widget("dog"); //猫听到狗叫了,也叫了 var cat=Ext.widget("cat"); //监听到狗叫 dog.on("dogbark",cat.bark); //老鼠听到狗叫了,吓跑了 var mice=Ext.widget("mice"); //监听到狗叫 dog.on("dogbark",mice.run); //主人听到狗叫,吵醒了 var human=Ext.widget("human"); //监听到狗叫 dog.on("dogbark",human.wake); //狗开始叫了 dog.bark();
输出的结果是:
是不是一连串效应产生了,这就是事件的魅力。
好了,这节就搞这么多了吧,下一篇我们将继续讲解事件,及他的用法!
有问题的同学可以加入我们的社区或群:13453484在线提问,我尽速解答。
作者:Louja
出处:http://html5mob.cnblogs.com 同步在:http://html5mob.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此声明,且在文章页面给出原文连接,否则保留追究法律责任的权利。