Ext JS在其历史上第一次进行了彻底的类体系的重构。新的架构应用到了几乎每一个Ext JS 4.x的类中,因此在使用它编写代码之前理解它是非常必要的。
本手册适用于所有在Ext JS 4.x中创建新类和继承已有类的程序员。分为四部分:
Ext JS 4包含超过300个类。目前Ext JS社区聚集了来自世界各地各种编程背景的二十多万名开发人员。对于这种规模的框架,我们在提供一般的编码架构方面面临巨大挑战:
JavaScript是一种无类型,面向原型(prototype-oriented)语言。因此,JavaScript本质上最强大的特性之一就是灵活性。它可以通过多种方式、不同编码风格和技术完成同一任务。但是高灵活性是以不可预测性为代价的。如果没有统一的结构,JavaScript代码是难以理解、维护和重用的。
另一方面,基于类(class-based)的编程仍然是OOP最常见的模型。基于类的语言(class-based languages)通常是强类型的(strong-typing),支持封装,且有标准的编码规范。通过使程序员们遵循一系列的规则,代码变得更加可预测、可扩展。然而,它们没有JavaScript等语言的动态性。
每种方式都有各自的优点和缺点。我们是否能够只取它们的优点,隐藏它们的缺点呢?答案是肯定的,我们在Ext JS 4中实现了这种解决方案。
代码中的classes、namespaces和文件名使用一致的命名规范提高了代码的条理性、结构性和可读性。
类名只能含有字母和数字字符。多数情况下应该避免使用数字,除非这些数字属于某个专业术语。不要使用下划线、连字符和任何其他的非字母数字的字符。例如:
类名应该使用点符号(.)分组到相应的包中。至少应该有一个唯一的顶层命名空间。例如:
MyCompany.data.CoolProxy MyCompany.Application
MyCompany.form.action.AutoLoad
缩写词也应该遵循驼峰命名法。例如:
类名直接映射到该类存储的路径。因此,每个类必然只对应一个文件。例如:
path/to/src是你的应用程序的类所在目录。所有的类都应该存储在这个根目录中,而且应该分为适当的包以便于开发、维护和部署。
如果你用过之前版本的Ext,那么你可能对使用Ext.extend创建类比较熟悉:
var MyWindow = Ext.extend(Object, { ... });
我们看一个例子:
My.cool.Window = Ext.extend(Ext.Window, { ... });
1.赋值之前,My.cool必须是一个存在的对象
2.在引用Ext.Window之前,它必须加载到页面上
第一项通常采用Ext.namespace(即Ext.ns)来解决。该方法递归地遍历对象/属性树(object/Property tree),并在不存在的情况下创建它。烦人的是,你需要在Ext.extend之前加上它们。
Ext.ns('My.cool'); My.cool.Window = Ext.extend(Ext.Window, { ... });
Ext JS 4消除了上述缺点,创建类时只要记住Ext.define一个方法即可。它的基本语法如下:
Ext.define(className, members, onClassCreated);
示例:
Ext.define('My.sample.Person', { name: 'Unknown', constructor: function(name) { if (name) { this.name = name; } return this; }, eat: function(foodType) { alert(this.name + " is eating: " + foodType); return this; } }); var aaron = Ext.create('My.sample.Person', 'Aaron'); aaron.eat("Salad"); // alert("Aaron is eating: Salad");
在Ext JS 4中,我们引入了专用的config属性,使得类在创建之前使用强大的Ext.class预处理器处理。包含以下特征:
这里是一个例子:
Ext.define('My.own.Window', { /** @readonly */ isWindow: true, config: { title: 'Title Here', bottomBar: { enabled: true, height: 50, resizable: false } }, constructor: function(config) { this.initConfig(config); return this; }, applyTitle: function(title) { if (!Ext.isString(title) || title.length === 0) { alert('Error: Title must be a valid non-empty string'); } else { return title; } }, applyBottomBar: function(bottomBar) { if (bottomBar && bottomBar.enabled) { if (!this.bottomBar) { return Ext.create('My.own.WindowBottomBar', bottomBar); } else { this.bottomBar.setConfig(bottomBar); } } } });
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 }); // Bottom bar's height is changed to 100
static成员可以使用statics config来定义:
Ext.define('Computer', { statics: { instanceCount: 0, factory: function(brand) { // 'this' in static methods refer to the class itself return new this({brand: brand}); } }, config: { brand: null }, constructor: function(config) { this.initConfig(config); // the 'self' property of an instance refers to its class this.self.instanceCount ++; return this; } }); 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" alert(Computer.instanceCount); // Alerts "2"
Ext JS 4提供了一些帮助调试和错误处理的特性。
throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');
英文原文链接:The Class System