此文接sencha类系统(一)
原译文地址:Sencha Class System processors
类继承
为了让类A继承类B,可以在定义A是为classMembers对象添加extend属性,属性值为‘B'
上代码:
Ext.define(‘My.sample.Developer’,{
extend:’My.sample.Person’,
code:function (language) {
alert(this.name+’is coding in ‘+language);
},
});
var tommy=new My.sample.Developer(‘tommy’);
tommy.walk(5);
tommy.code(‘JavaScript’);
上例中My.sample.Person用单引号引起来了,这是标准的写法。使用字符串类型的类名,你不需要考虑关于依赖的问题,因为Ext.Loader在它们不存在的时候动态的加载它们。两个引号为我们的编程带来了极大的好处。
可以在重写方法中使用this.callParent调用父类中被重写重写的方法,接着上面的例子我们重写Person类的walk方法。
// My/sample/Developer.js Ext.define('My.sample.Developer', { extend: 'My.sample.Person' code: function(language) { /* … */ }, walk: function(steps) { if (steps > 100) { alert("Are you serious? That's too far! I'm lazy…"); } else { return this.callParent(arguments); } } }); // app.js var tommy = new My.sample.Developer('Tommy'); tommy.walk(50); // alerts "Tommy is walking 50 steps" tommy.walk(101); // alerts "Are you serious? That's too far! I'm lazy…"
我们将walk接受的参数直接传递给父类的的walk方法,当然这不是必须的,比如就可以this.callParent([50]),但是参数必须是数组或arguemtns
Class Mixins
Mixins是一组可以在类间共享的具有重用性的features。称为ablities可能会更恰当。在Sencha中mixins只是简单的类。任何类都可以使用mixins,senha中有一些关于mixins很好的例子:
Identifiable,赋予目标类一个getId方法成成唯一ID
Observable,赋予目标类事件处理的能力
Traversable,赋予目标类tree-like API
一个类可以拥有多于一个的mixin,让类A中混合进类B和类C,可以在定义类A时添加mixins属性,属性值为一个描述 B和C的对象。为了形象的说明mixins的好处,我们定义三个类代表一个人可以拥有的三种不同能力,命名为:
CanSing
CanPlayGuitar
CanComposeSongs
然后我们创建一个CoolGuy类和一个Musician方法。一个CoolGuy可以CanSing和CanPlayGuitar,一个Musician可以CanPlayGuitar和CanComposeSongs,CanSing。
// My/sample/CanSing.js Ext.define('My.sample.CanSing', { sing: function(songName) { alert("I'm singing " + songName); } }); // My/sample/CanPlayGuitar.js Ext.define('My.sample.CanPlayGuitar', { playGuitar: function() { alert("I'm playing guitar"); } }); // My/sample/CanComposeSongs.js Ext.define('My.sample.CanComposeSongs', { composeSongs: function() { alert("I'm composing songs"); return this; } }); // My/sample/CoolGuy.js Ext.define('My.sample.CoolGuy', { extend: 'My.sample.Person', mixins: { canSing: 'My.sample.CanSing', canPlayGuitar: 'My.sample.CanPlayGuitar' } }); // My/sample/Musician.js Ext.define('My.sample.Musician', { extend: 'My.sample.Person', mixins: { canSing: 'My.sample.CanSing', canPlayGuitar: 'My.sample.CanPlayGuitar', canComposeSongs: 'My.sample.CanComposeSongs' } }); // app.js var nicolas = new My.sample.CoolGuy("Nicolas"); nicolas.sing("November Rain"); // alerts "I'm singing November Rain"
mixins是通过键值对声明的,key可以用来引用被类重写的mixins方法。上代码:
// My/sample/CoolGuy.js Ext.define('My.sample.CoolGuy', { extend: 'My.sample.Person', mixins: { canSing: 'My.sample.CanSing', canPlayGuitar: 'My.sample.CanPlayGuitar' }, sing: function() { alert("Attention!"); // this.mixins is a special object holding references to all mixins' prototypes return this.mixins.canSing.sing.apply(this, arguments); } }); // app.js var nicolas = new My.sample.CoolGuy("Nicolas"); nicolas.sing("November Rain"); // alerts "Attention!" // alerts "I'm singing November Rain"
此外,因为我们在mixins中使用了字符串类型的类名,所以这些类也会在需要的时候自动加载。
Class Configuration
这是Ext JS 4.1+和sencha touch 2.0+才有的特性。Ext JS 4.0并没有使用。
通过在类声明对象的config对象属性,可以定义类的公共API。config中的每一个配置项在没有自己声明getter和setter时都会有自己自动生成的setter和getter方法。
举例如下:
Ext.define('My.sample.Person', { config: { name: 'Mr. Unknown', age: 0, gender: 'Male' }, constructor: function(config) { this.initConfig(config); return this; } /* … */ });
通过config在Person类的定义中添加name,age,gender项:
在类中,this.name指向默认值’Mr. Unknown’,但是可以通过使用setter和getter方法来进行更安全的访问。
var jacky = new Person({ name: "Jacky", age: 35 }); alert(jacky.getAge()); // alerts 35 alert(jacky.getGender()); // alerts "Male" jacky.walk(10); // alerts "Jacky is walking 10 steps" jacky.setName("Mr. Nguyen"); alert(jacky.getName()); // alerts "Mr. Nguyen" jacky.walk(10); // alerts "Mr. Nguyen is walking 10 steps"
我们在contructor中调用this.initConfig,并将config传递做参数,这期间有两个很重要的操作:
对象实例化时的config对象与默认的config对象合并;(这段原文我也没有理解的很好,大家可以参照原文)
所有相关属性的setter方法被调用,参数是合并后的值。
除了可以保存相应的值外,框架内的setters还有两个艰巨的任务:
在真正设置值前,过滤/验证/转换提供的参数值。
当值被设置或变化后,通知/post-processing
为了让这种模式更加标准化,自动生成的setters提供了另外两个模板函数供重写,比如config中的foo项就会有applyFoo和updateFoo方法,前者在设置值之前执行,后者在值设置之后执行。这样我们使用这种方法可以完善上面我们的例子,比如age属性明显只能是数字。
Ext.define('My.sample.Person', { config: { /* … */ }, constructor: { /* … */ } applyAge: function(age) { if (typeof age != 'number' || age < 0) { console.warn("Invalid age, must be a positive number"); return; } return age; }, updateAge: function(newAge, oldAge) { // age has changed from "oldAge" to "newAge" this.fireEvent('agechange', this, newAge, oldAge); } /* … */ }); var jacky = new Person({ name: "Jacky", age: 'invalid' }); alert(jacky.getAge()); // alerts 0 alert(jacky.setAge(-100)); // alerts 0 alert(jacky.getAge()); // alerts 0 alert(jacky.setAge(35)); // alerts 0 alert(jacky.getAge()); // alerts 35
所以当使用config属性时,不应该自己定义setter和getter,相反应该重写apply*和update*方法,你的代码中应该只包含应该有的逻辑。
类依赖(Class Dependencies)
在一个类的方法中使用另外一个类的场景很常见。想让Ext.Loader知道我们的类依赖,只需要在类定义时声明数组类型的requires属性。上代码:
Ext.define('My.sample.Person', { requires: ['My.sample.Validator', 'My.sample.Formatter'], /* … */ applyAge: function(age) { if (!My.sample.Validator.validateAge(age)) { console.warn("Invalid age, must be a positive number"); return; } return age; }, applyName: function(name) { return My.sample.Formatter.capitalize(name); } /* … */ });
Post-processors:
Singleton
在Ext JS中,Singleton是一个类只有一个实例。将类声明中的singleton设为true,即可在类创建结束后创建一个类实例,然后赋值给命名空间对象的相应属性。
上代码:
Ext.define('My.sample.Validator', { singleton: true, validateNumber: function(number) { return typeof number == 'number'; } validateAge: function(number) { return this.validateNumber(number) && number >= 0; } /* … */ });
alert(My.sample.Validator.validateNumber('invalid')); // alerts false
上面的My.sample.Validator是一个类实例,而不是一个类。可以使用Ext.getClass获取实例的类。
var ValidatorClass = Ext.getClass(My.sample.Validator);
Alternative Class Names
有时候为了为了方便或向下兼容,会为类创建别名。这是可以使用alternateClassName属性。属性可以是一个字符串(一个名字),字符串数组(多个名字)
Ext.define('My.sample.form.Field', { alternateClassName: ['My.FormField', 'My.sample.FormField'] /* … */ }); // My.sample.form.Field, My.FormField and My.sample.FormField now reference the same class
总结
sencha类系统是在Senha Javascript框架中使用面向对象编程的不二选择。现在它已经很稳定,可以在代码中使用它。我们会不断改进类系统以减轻你日复一日重复编程……。(最后就是吹吹牛,讲讲口号)