Ext JS 4 类体系重构:命名规范、定义方式与调试实战

作者:半夏时间:2026-10-26 22:05:57浏览:222

本文深入解析 Ext JS 4 对类体系的重构,涵盖从底层架构到实际编码的完整指南。重点介绍基于类的编程优势、严格的命名规范(类、方法、文件),以及使用 Ext.define 替代旧版 Ext.extend 的正确方式。通过配置系统(config)、静态成员定义及错误调试技巧,帮助开发者构建可扩展、易维护的 Ext JS 应用。

Ext JS 4 类体系重构概述

Ext JS 4 在底层对类体系进行了彻底重构,这是该框架历史上首次大规模调整。新架构已应用于几乎每个 Ext JS 4 类中,因此在开始编码前充分理解这一机制至关重要。


本手册面向希望创建新类或继承 Ext JS 4 现有类的开发人员,内容分为四个部分:


第一部分为“概述”,阐述构建健壮类体系的必要性。


第二部分为“命名规范”,探讨类、方法、属性、变量及文件命名的最佳实践。


第三部分为“实践”,提供详细的逐步代码示例。


第四部分为“错误处理和调试”,分享处理异常的实用技巧。



一. 概述

Ext JS 4 包含超过 300 个类,拥有超过 200,000 名来自全球不同编程背景的开发者。面对如此庞大的框架,我们面临着一项巨大挑战:提供一套通用的代码体系结构。


该体系结构需友好且易于学习。


同时需支持快速开发、易于调试和简单部署。


此外,代码必须组织良好,具备可扩展性和可维护性。


JavaScript 是一种无类型、基于原型的语言,其最大优势在于灵活性。通过不同编码风格和技巧,可以用多种方式完成同一任务。然而,这种灵活性若缺乏统一结构,会导致代码难以理解、维护和重用。


基于类的编程采用最流行的面向对象(OOP)模型。基于类的语言通常是强类型的,提供封装和标准编码约定。遵循统一的编码规则有助于生成可预测、可扩展和可延伸的代码,但代价是失去了 JavaScript 等语言的动态特性。


每种方法各有优劣,我们能否结合两者的优点并隐藏缺点?答案是肯定的,Ext JS 4 已实现这一解决方案。



二. 命名规范

命名规范详解

在代码中始终使用一致的基于类、命名空间和文件名的命名规范,有助于保持代码的组织性、结构化和可读性。


1) 类

类名仅可包含字母数字字符,数字在大多数情况下不被允许,除非属于技术术语。禁止使用下划线、连字符或其他非字母数字字符。例如:


MyCompany.useful_util.Debug_Toolbar 是不允许的。


MyCompany.util.Base64 是允许的。


类名应通过对象点表达式(.)属性放置到适当的命名空间中。至少,类名应包含一个唯一的顶层命名空间。例如:


MyCompany.data.CoolProxy


MyCompany.Application


顶层命名空间和类名应采用驼峰命名法,其余部分全部小写。例如:


MyCompany.form.action.AutoLoad


非 Sencha 发布的 Ext JS 类不得使用 Ext 作为顶层命名空间。


缩略词也应遵循上述驼峰命名规范。例如:


Ext.data.JsonProxy 优于 Ext.data.JSONProxy


MyCompany.util.HtmlParser 优于 MyCompary.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"



三. 实践
1. 声明

类定义实践:从旧方法到新语法

1.1) 老的方法


如果您使用过早期版本的 Ext JS,肯定熟悉使用 Ext.extend 创建类的方式:


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


这种方法易于创建继承自其他类的新类,但除了直接继承,我们缺乏创建类其他方面(如配置、静态配置和混入类)的良好 API,这些内容将在后文详细回顾。


让我们看另一个例子:


My.cool.Window = Ext.extend(Ext.Window, { ... });


在此示例中,我们希望创建一个新的命名空间类并继承 Ext.Window,这里有两个问题需要解决:


My.cool 必须是已存在的命名空间对象,以便我们将 Window 分配为其属性。


Ext.Window 必须存在且已加载,以便引用它。


第一点通常通过 Ext.namespace(别名 Ext.ns)解决,该方法递归创建不存在的对象。令人烦恼的是,您必须始终记得在 Ext.extend 之前添加它们:


Ext.ns('My.cool');My.cool.Window = Ext.extend(Ext.Window, { ... });


然而第二个问题较难解决,因为 Ext.Window 可能依赖许多其他类,它可能直接或间接继承自那些依赖类,而这些依赖类又依赖于其他类。因此,在 Ext JS 4 之前编写的应用程序通常会引入整个库文件 ext-all.js,尽管可能仅需其中很小一部分。


1.2) 新的方法


Ext JS 4 消除了所有这些缺点,您只需记住创建类的唯一方法是:Ext.define,其基本语法如下:


Ext.define(className, members, onClassCreated);


className:类名


members 是一个大对象,代表类成员的集合,由一系列键值对组成。


onClassCreated 是一个可选回调函数,当类的所有依赖项准备好且类完全创建时被调用。此回调函数在许多情况下很有用,我们将在第四部分深入讨论。


示例:


代码如下:

 
Ext.define('My.sample.Person',{
name: 'Unknown',
constructor: function(name) {
if (name) {
this.name = name;
}}, 
eat: function(foodType) {
alert(this.name + " is eating: " + foodType); }});
var aaron = Ext.create('My.sample.Person', 'Aaron');
aaron.eat("Salad"); // alert("Aaron is eating: Salad");

注意,我们使用 Ext.create() 方法创建 My.sample.Person 的实例。当然也可以使用 new 关键字(new My.sample.Person()),但我们建议养成始终使用 Ext.create 的习惯,因为它可以利用动态加载功能。更多信息请参阅 Ext JS 4 入门指南。



2. 配置

配置系统与静态成员管理

在 Ext JS 4 中,我们引入了专用的 config 属性,它会在类创建前由强大的预处理器类 Ext.Class 处理,具有以下特性:


配置从其他类成员完全封装。


每个 config 属性的 getter 和 setter 方法会在类原型中自动生成,如果类中未定义这些方法。


同时,每个 config 属性也会生成一个 apply 方法,自动生成的 setter 方法会在内部设置值之前调用此 apply 方法。若要在设置值之前运行自定义逻辑,可覆盖此 apply 方法。如果 apply 没有返回值,setter 方法将不会设置值。让我们看看下面的 applyTitle 方法:


下面的例子定义了一个新类:


代码如下:

 
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); },
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


3. 静态配置

静态配置成员可以使用 statics 属性来定义:


代码如下:

 
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 ++; }});
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 包含了一些有用的特性,可以帮助你调试和错误处理:


你可以使用 Ext.getDisplayName() 方法来获取任何方法的显示名称,这在抛出错误时特别有用,可用于在错误描述中显示类名和方法名:


throw new Error('[' + Ext.getDisplayName(arguments.callee) + '] Some message here');


当错误从由 Ext.define() 定义的类的任何方法中抛出时,如果你使用的基于 WebKit 的浏览器(Chrome 或者 Safari)的话,你会在调用堆栈中看到方法名和类名。例如,下面是从 Chrome 中看到的堆栈信息:


Ext JS 4 类体系重构概述
作者最新文章