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看看控制台输出的结果:

hello 我的名字叫:小黑 我今年:5岁!
你太不厚道了,不能给我取这样的名字
小黑
大黑
 
可以看出,当我们给它改名为王八蛋的时候,它反抗了,名字没有改成功。后面我们让它叫大黑,它就接受了!
呵呵,学会了点么?多去练习下撒
 
 

下面继续玩玩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();

输出的结果是:

Sencha touch 开发系列:类系统

是不是一连串效应产生了,这就是事件的魅力。

好了,这节就搞这么多了吧,下一篇我们将继续讲解事件,及他的用法!

有问题的同学可以加入我们的社区或群:13453484在线提问,我尽速解答。

作者:Louja
出处:http://html5mob.cnblogs.com 同步在:http://html5mob.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此声明,且在文章页面给出原文连接,否则保留追究法律责任的权利。 

你可能感兴趣的:(Sencha Touch)