ExtJS 4 的类体系

历史上第一次,Ext JS通过新的类体系进行了彻底的重构。新的框架支持几乎每个单独的用Ext JS 4.x写的类,因此在你开始编码之前理解彻底比较重要。

这个指南是为任何想创造新的或者扩展现有的Ext JS 4.x类的开发者而准备。分成4个部分:

  • 第一部分:“综述”解释了自动类系统的需求
  • 第二部分:“命名转换”讨论了命名类、方法、属性、变量和文件的最佳实践
  • 第三部分:“动手实践”提供了详细的一步一步的编码样例
  • 第四部分:“错误处理&调试”给出了如何处理异常的有效提示&技巧

I. 综述

Ext JS 4承载了超过300个类。我们拥有一个来自全世界拥有不同编程背景的超过200,000名开发者的巨大的社区。面对如此规模的框架,我们面临的是提供通用编码架构的巨大挑战:

  • 常见并简单易学
  • 快速开发、容易调试、易于部署
  • 良好组织、可扩展和维护
JavaScript是一个无类别的、面向原型的语言。因此本质上,该语言最大的特征是灵活。它可以用很多不同的方法、以多种不同的编码风格和技术来解决同一个问题。然而,这个特征带来了不可预测性的代价。没有一个标准的结构,JavaScript代码会很难理解、维护和复用。

另一方面,基于类的编程仍然是最流行的OOP模型。基于类的语言通常需要强类型,提供封装,使用标准编码约定。通常让开发者遵循大量的规则,写出的代码更可能是可预测的、可扩展的和可随时间而伸缩的。然而,在像JavaScript这样的语言中没有相同的动态兼容性。

每个方法都有其优点和缺点,但我们可否在避免不好的部分的同时拥有好的部分呢?答案是肯定的,我们将在Ext JS 4中实现这个解决方法。

II.命名约定

在你的代码基础中为类、命名空间和文件名使用一致的命名约定有助于保持你的代码有组织、有结构和可读性。

1)类

类的名字可仅仅包含字母数字的字符。在大多数情况下允许但不鼓励使用数字,除非他们属于技术术语。不要使用下划线、连结号,或者其他非字母数字的字符。例如:

  • MyCompany.useful_util.Debug_Toolbar是不鼓励的
  • MyCompany.util.Base64是可以接受的

类名应该组成拥有近似并合理的、使用对象性质的点号(.)命名空间的包。最少应该有一个独立的最高级的、后接类名的命名空间。比如:

1 MyCompany.data.CoolProxy
2 MyCompany.Application
最高级的命名空间和真实的类名应该使用驼峰命名法,其他的都应该是小写的。例如:
1 MyCompany.form.action.AutoLoad
不通过Sencha分布的类不应该使用Ext作为最高级的命名空间。首字母缩略词也应该遵循上面提到的驼峰命名法。例如:
  • Ext.data.JsonProxy而不是Ext.data.JSONProxy
  • MyCompany.util.HtmlParser而不是MyCompany.parser.HTMLParser
  • MyCompany.server.Http而不是MyCompany.server.HTTP

2) 源文件

类的名字直接映射到它们存储的文件路径上。结果就是一定是单个文件只有一个类。例如:

  • Ext.util.Observable在路径/to/src/Ext/util/Observable.js上存储
  • Ext.form.action.Submit在路径/to/src/Ext/form/action/Submit.js上存储
  • MyCompany.chart.axis.Numeric在路径/to/src/MyCompany/chart/axis/Numeric.js上存储
路径/to/src是你应用的类的文件夹。所有的类应该放在这个通用根目录下,应该为了最佳开发、维护和部署而使用合适的命名空间。

3)方法和变量

  • 和类名相似,方法和变量名可以仅包含字母数字字符。在大部分情况下允许但不鼓励使用数字,除非它们属于技术用语。不要使用下划线、连结号,或者其他非字母数字字符。
  • 方法和变量名应该总是使用驼峰命名法。这对首字母缩略词同样有效。
  • 例子:
  • 可接受的方法名:encodeUsingMd5() getHtml()而不是getHTML() getJsonResponse()而不是getJSONResponse() parseXmlContent()而不是parseXMLContent()
  • 可接受的变量名:var isGoodName var base64Encoder var xmlReader var httpServer

4)属性

  • 类属性名和上面提到的方法和变量遵循相同的约定,除了它们是静态常量的情况。
  • 静态常量类属性应该全大写。例如:
  • Ext.MessageBox.YES = "Yes"
  • Ext.MessageBox.NO = "No"
  • MyCompany.alien.Math.PI = "4.13"

III. 动手实践

1.声明

1.1)旧方法

如果你曾经使用过Ext JS以前的版本,你一定对使用Ext.extend来创建一个类很熟悉:


1 var MyWindow = Ext.extend(Object, { ... });

这个方法在从其他类继承而创建新类时很容易使用。然而,不像直接继承,我们并没有用做创建类的其他方面的固定API,比如配置、静态和混合。我们将简短的详细回顾这些内容。

让我们来看下另一个例子:

1 My.cool.Window = Ext.extend(Ext.Window, { ... });
在这个例子中,我们想对新类设置  命名空间,并让它从  Ext.Window中扩展。我们需要强调两点需要注意的地方:
  1. My.cool在我们分配Window作为它的属性前,需要是个已存在的对象
  2. Ext.Window在它可以被引用前,需要存在/载入页面中
第一条经常使用Ext.namespace(别名Ext.ns)来解决。这个方法在对象/属性树上横向递归,如果它们不存在就创建它们。无聊的地方在于你需要时时记住在Ext.extend上添加它们。

1 Ext.ns('My.cool');
2 My.cool.Window = Ext.extend(Ext.Window, { ... });
然而,第二个问题很难强调,因为  Ext.Window可能依赖于它直接/间接继承的其他类,反过来,这些依赖也可能依赖其他存在的类。因为这个原因,在Ext JS 4前写的应用经常以ext-all.js的形式包含整个库,尽管他们可能仅需要框架的一小部分。

1.2) 新方法

Ext JS 4取消了那些用来创建类的,需要记的,仅有一个单独方法的所有那些缺点。基本语法如下:

1 Ext.define(className, members, onClassCreated);
  • className:类名
  • members是以键/值对形式表示类成员的集合的一个对象
  • onClassCreated是个可选调用的回调函数,当这个类的所有依赖都已经准备好了,并且类自身也已经完全创建。根据第四部分
例子:

01 Ext.define('My.sample.Person', {
02     name: 'Unknown',
03  
04     constructor: function(name) {
05         if (name) {
06             this.name = name;
07         }
08     },
09  
10     eat: function(foodType) {
11         alert(this.name + " is eating: " + foodType);
12     }
13 });
14  
15 var aaron = Ext.create('My.sample.Person''Aaron');
16     aaron.eat("Salad"); // alert("Aaron is eating: Salad");
注意我们使用  Ext.create()方法创建了My.sample.Person的新实例。我们可以使用new关键字(new My.sample.Person())。然而建议养成使用  Ext.create的习惯,因为它可以使你利用动态载入的优势。关于动态载入的更多信息可以看  入门指南

2. 配置

在Ext JS 4中,我们引入了专用配置属性,可以在类创建前使用强大的Ext.Class预处理来处理。特性包括:

  • 配置对于其他类成员完全封装
  • 每个配置属性的获得者和设置者,及方法在类原型中随类创建而自动生成,若类中没有定义过这些方法。
  • 一个apply方法也为每个配置属性生成。自动生成的设置者方法在赋值前在内部调用apply方法。如果你需要在赋值前运行自定义逻辑,可以重写apply方法。如果apply不返回值,那么设置者将不赋值。下面是一个apply的例子。
下面是个例子:

01 Ext.define('My.own.Window', {
02     /** @readonly */
03     isWindow: true,
04  
05     config: {
06         title: 'Title Here',
07  
08         bottomBar: {
09             height: 50,
10             resizable: false
11         }
12     },
13  
14     constructor: function(config) {
15         this.initConfig(config);
16     },
17  
18     applyTitle: function(title) {
19         if (!Ext.isString(title) || title.length === 0) {
20             alert('Error: Title must be a valid non-empty string');
21         }
22         else {
23             return title;
24         }
25     },
26  
27     applyBottomBar: function(bottomBar) {
28         if (bottomBar) {
29             if (!this.bottomBar) {
30                 return Ext.create('My.own.WindowBottomBar', bottomBar);
31             }
32             else {
33                 this.bottomBar.setConfig(bottomBar);
34             }
35         }
36     }
37 });
38  
39 /** A child component to complete the example. */
40 Ext.define('My.own.WindowBottomBar', {
41     config: {
42         height: undefined,
43         resizable: true
44     }
45 });
下面是如何使用它的例子:

01 var myWindow = Ext.create('My.own.Window', {
02     title: 'Hello World',
03     bottomBar: {
04         height: 60
05     }
06 });
07  
08 alert(myWindow.getTitle()); // alerts "Hello World"
09  
10 myWindow.setTitle('Something New');
11  
12 alert(myWindow.getTitle()); // alerts "Something New"
13  
14 myWindow.setTitle(null); // alerts "Error: Title must be a valid non-empty string"
15  
16 myWindow.setBottomBar({ height: 100 });
17  
18 alert(myWindow.getBottomBar().getHeight()); // alerts 100

3.静态

静态成员可以使用static配置来定义

01 Ext.define('Computer', {
02     statics: {
03         instanceCount: 0,
04         factory: function(brand) {
05             // 'this' in static methods refer to the class itself
06             return new this({brand: brand});
07         }
08     },
09  
10     config: {
11         brand: null
12     },
13  
14     constructor: function(config) {
15         this.initConfig(config);
16  
17         // the 'self' property of an instance refers to its class
18         this.self.instanceCount ++;
19     }
20 });
21  
22 var dellComputer = Computer.factory('Dell');
23 var appleComputer = Computer.factory('Mac');
24  
25 alert(appleComputer.getBrand()); // using the auto-generated getter to get the value of a config property. Alerts "Mac"
26  
27 alert(Computer.instanceCount); // Alerts "2"

IV. 错误处理 & 调试

Ext JS 4 包含了一些有用的特性,将帮助你来调试和处理错误。

  • 你可以使用Ext.getDisplayName()来得到任何方法的显示名字。这在抛出在描述有类名和方法名的描述是特别有用:

1 throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');
  • 当使用Ext.define()抛出任何类的任何方法的错误时,如果你使用基于Webkit的浏览器(Chrome或者Safari)时,你可以在调用堆栈里查看方法和类名。例如,下面是在Chrome中的样子:
ExtJS 4 的类体系_第1张图片

也可以看

  • 动态载入和新类系统
  • Ext JS 4中的类:在钩子之下
  • 类定义管道

你可能感兴趣的:(浏览器,编码,语言,ExtJs,Something)