许多类在使用配置对象创建(实例化)类时具有使用的快捷名称。快捷名称称为别名
(如果类扩展 Ext.Component,则称为xtype
)。别名/xtype 列在适用类的类名旁边以供快速参考。
框架类或其成员可以指定为私有
或受保护
。否则,类/成员为公共
。公共
、受保护
和私有
是访问描述符,用于传达如何以及何时应使用类或类成员。
公共类和类成员可供任何其他类或应用程序代码使用,并且可以作为主要产品版本中稳定且持久的类和类成员。公共类和成员可以通过子类安全地进行扩展。
受保护类成员是稳定的公共
成员,旨在由拥有类或其子类使用。受保护的成员可以通过子类安全地进行扩展。
私有类和类成员由框架内部使用,不打算由应用程序开发人员使用。私有类和成员可以在任何时候更改或从框架中省略,且不应在应用程序逻辑中依赖它们。
静态
标签。*请参见下面的静态。下面是一个示例类成员,我们可以对其进行剖析以显示类成员的语法(在这种情况下,从 Ext.button.Button 类中查看的 lookupComponent 方法)。
我们来看看成员行中的每一部分
lookupComponent
)( item )
)Ext.Component
)。对于不返回 undefined
以外任何内容的方法,可以省略此项,或者可能显示用正斜杠 /
分隔的多个可能值,表示返回的内容可能取决于方法调用的结果(即,如果 get 方法调用成功,则方法可能返回一个组件,如果失败,则返回 false
,将显示为 Ext.Component/Boolean
)。PROTECTED
- 请参见下面的标志部分)Ext.container.Container
)。如果成员来自当前类,则源类将显示为蓝色链接;如果成员是从祖先或混合类继承的,则显示为灰色。查看源
)item : Object
)进行列出。undefined
以外的值,则“返回”部分将注明返回的类或对象类型以及描述(示例中为 Ext.Component
)自 3.4.0 起可用
- 示例中未显示)默认为:false
)API 文档使用许多标志来进一步传达类成员的功能和意图。标签可以用文本标签、缩写或图标表示。
classInstance.method1().method2().etc();
false
,则标记为可预防的事件将不会触发- 表示框架类
- 单例框架类。*有关更多信息,请参见单例标志
- 组件类型框架类(Ext JS 框架中扩展 Ext.Component 的任何类)
- 表示类、成员或指南在当前查看的版本中是新的
- 表示类型为 config
的类成员
- 表示类型为 property
的类成员
- 表示类型为 method
的类成员
- 表示类型为 event
的类成员
- 表示类型为 theme variable
的类成员
- 表示类型为 theme mixin
的类成员
- 表示类、成员或指南在当前查看的版本中是新的
在 API 文档页面上类名称正下方是一行按钮,对应于当前类拥有的成员类型。每个按钮按类型显示成员数(此计数在应用筛选器时更新)。单击按钮将导航到该成员部分。将鼠标悬停在成员类型按钮上将显示一个弹出菜单,其中包含该类型的所有成员,以便快速导航。
与类配置选项相关的 Getter 和 Setter 方法将显示在方法部分以及 API 文档和成员类型菜单的配置部分中,它们位于它们所使用的配置正下方。Getter 和 Setter 方法文档将位于配置行中,以便于参考。
您的页面历史记录保存在本地存储中,并显示在顶部标题栏正下方(使用可用空间)。默认情况下,仅显示与您当前查看的产品/版本匹配的搜索结果。您可以通过单击历史记录栏右侧的 按钮并选择“全部”单选选项来展开显示的内容。这将在历史记录栏中显示所有产品/版本的所有近期页面。
在历史记录配置菜单中,您还将看到最近访问的页面列表。结果按“当前产品/版本”和“全部”单选选项进行筛选。单击 按钮将清除历史记录栏以及保存在本地存储中的历史记录。
如果在历史记录配置菜单中选择“全部”,则将启用“在历史记录栏中显示产品详细信息”复选框选项。选中后,每个历史记录页面的产品/版本将与历史记录栏中的页面名称一起显示。将光标悬停在历史记录栏中的页面名称上也将以工具提示的形式显示产品/版本。
可以使用页面顶部的搜索字段搜索 API 文档和指南。
在 API 文档页面上,还有一个筛选器输入字段,它使用筛选器字符串筛选成员行。除了按字符串筛选外,您还可以按访问级别、继承和只读筛选类成员。这是使用页面顶部的复选框完成的。
API 类导航树底部的复选框筛选类列表,以包括或排除私有类。
单击空搜索字段将显示您最近的 10 次搜索,以便快速导航。
每个 API 文档页面(Javascript 基本页面除外)都有一个与该类相关的元数据的菜单视图。此元数据视图将包含以下一个或多个
Ext.button.Button
类有一个备用类名 Ext.Button
)。备用类名通常用于向后兼容。默认情况下,可运行示例(小提琴)在页面上展开。你可以使用代码块左上角的箭头单独折叠和展开示例代码块。你还可以使用页面右上角的切换按钮切换所有示例的折叠状态。切换所有状态将在页面加载之间记住。
默认情况下,类成员在页面上折叠。你可以使用成员行左侧的箭头图标或全局使用右上角的展开/折叠所有切换按钮展开和折叠成员。
在较窄的屏幕或浏览器上查看文档将导致针对较小尺寸优化视图。桌面和“移动”视图之间的主要区别是
可以通过单击 API 文档页面顶部的类名来查看类源。可以通过单击成员行右侧的“查看源”链接来查看类成员的源。
Sencha Cmd 的主要组件之一是其编译器。本指南介绍如何编写代码以充分利用编译器并为未来的框架感知优化做好准备。
建议在继续之前阅读以下指南
Sencha Cmd 编译器不是以下工具的替代品
这些工具为 JavaScript 开发人员解决了不同的问题,并且在 JavaScript 领域非常出色,但对 Sencha 框架特性(如用于声明类的 Ext.define
)没有了解。
Sencha Cmd 编译器的作用是提供框架感知优化和诊断。一旦代码通过 Sencha Cmd 编译器,它便可以用于更通用的工具。
事实证明,此类优化可以显著改善浏览器对 JavaScript 代码的“摄入”时间,尤其是在旧版浏览器上。
然而,为了让编译器提供这些好处,现在重要的是要了解编译器可以“理解”的编码约定,因此可以针对你进行优化。遵循本指南中描述的约定可确保你的代码定位于充分利用当前和未来的 Sencha Cmd。
动态加载器和之前的 JSBuilder 始终对类的组织方式做出某些假设,但如果不遵循这些准则,它们不会受到严重影响。这些准则与 Java 非常相似。
回顾一下,这些准则如下
Ext.define
语句。Ext.define("MyApp.foo.bar.Thing", ...
的源文件的名称为“Thing.js”。Ext.define("MyApp.foo.bar.Thing", ...
,源文件位于以“/foo/bar”结尾的路径中。在内部,编译器将源文件和类视为基本同义词。它不会尝试拆分文件以删除不需要的类。只有完整的文件才会被选中并包含在输出中。这意味着如果源文件中的任何类是必需的,则文件中的所有类都将包含在输出中。
为了让编译器能够在类级别选择代码,必须在每个文件中只放置一个类。
Sencha 类系统提供 Ext.define
函数以启用高级面向对象编程。编译器认为 Ext.define
实际上是一种“声明式”编程形式,并相应地处理“类声明”。
显然,如果 Ext.define
被理解为声明,那么类主体的内容不能在代码中动态构建。虽然这种做法很少见,但它是一种有效的 JavaScript。但正如我们在下面的代码形式中所看到的,这与编译器理解其解析代码的能力背道而驰。动态类声明通常用于执行由编译器的其他特性更好地处理的任务。有关这些特性的详细信息,请参阅Sencha 编译器参考。
编译器理解此声明式语言的以下“关键字”
requires
uses
extend
mixins
statics
alias
singleton
override
alternateClassName
xtype
为了让编译器识别你的类声明,它们需要遵循以下形式之一。
大多数类使用如下简单的声明
Ext.define('Foo.bar.Thing', {
// keywords go here ... such as:
extend: '...',
// ...
});
第二个参数是类主体,它由编译器作为类“声明”处理。
注意:在所有形式中,都在全局作用域中调用 Ext.define
。
在某些用例中,类声明被包装在一个函数中,为类方法创建一个闭包作用域。在所有各种形式中,对于编译器来说,至关重要的是,该函数以 return
语句结尾,该语句将类主体作为对象字面量返回。编译器不识别其他技术。
为了简化下面描述的这种技术的旧形式,Ext.define
理解,如果给定一个函数作为其第二个参数,它应该调用该函数来生成类主体。它还将对类的引用作为单个参数传递,以通过闭包范围方便地访问静态成员。在框架内部,这是闭包范围最常见的原因。
Ext.define('Foo.bar.Thing', function (Thing) {
return {
// keywords go here ... such as:
extend: '...',
// ...
};
});
注意: 此形式仅在 Ext JS 4.1.2 及更高版本和 Sencha Touch 2.1 及更高版本中受支持。
在以前的版本中,不支持“函数形式”,因此只是立即调用该函数
Ext.define('Foo.bar.Thing', function () {
return {
// keywords go here ... such as:
extend: '...',
// ...
};
}());
此形式和下一个形式通常用于安抚 JSHint(或 JSLint)之类的工具。
Ext.define('Foo.bar.Thing', (function () {
return {
// keywords go here ... such as:
extend: '...',
// ...
};
})());
立即调用“函数形式”的另一种变体,以安抚 JSHint/JSLint。
Ext.define('Foo.bar.Thing', (function () {
return {
// keywords go here ... such as:
extend: '...',
// ...
};
}()));
类声明在其多种形式中最终包含“关键字”。每个关键字都有自己的语义,但有许多关键字具有共同的“形状”。
extend
和 override
关键字只接受字符串文字。
这些关键字也是互斥的,因为在任何声明中只能使用一个关键字。
以下关键字都具有相同的形式
requires
uses
alias
alternateClassName
xtype
这些关键字支持的形式如下。
只是一个字符串
requires: 'Foo.thing.Bar',
//...
一个字符串数组
requires: [ 'Foo.thing.Bar', 'Foo.other.Thing' ],
//...
mixins
的形式使用对象文字,给定 mixin 的名称可以加引号,也可以不加引号
mixins: {
name: 'Foo.bar.Mixin',
'other': 'Foo.other.Mixin'
},
//...
Mixins 也可以指定为 String[]
mixins: [
'Foo.bar.Mixin',
'Foo.other.Mixin'
],
//...
这种方法依赖于 mixin 类的 mixinId
,但也允许接收类控制 mixin 顺序。如果 mixins 具有重叠的方法或属性,并且接收类想要控制哪个 mixin 提供重叠的方法或属性,这一点很重要。
statics
关键字此关键字将属性或方法放在类上,而不是放在每个实例上。这必须是一个对象文字。
statics: {
// members go here
},
// ...
singleton
关键字此关键字在历史上仅与布尔值“true”一起使用
singleton: true,
还支持以下(冗余)用法
singleton: false,
在 Ext JS 4.1.0 和 Sencha Touch 2.0 中,Ext.define
获得了管理覆盖的能力。从历史上看,覆盖已用于修补代码以解决错误或添加增强功能。由于执行 Ext.override
方法所需的时间,这种用法随着动态加载器的引入而变得复杂。此外,在具有许多覆盖的大型应用程序中,并非所有代码库中的覆盖都是所有页面或构建所需的(例如,如果不需要目标类)。
一旦类系统和加载器理解覆盖,这一切都发生了变化。这种趋势只会随着 Sencha Cmd 而继续。编译器理解覆盖及其依赖项影响和加载顺序问题。
将来,编译器将在消除被覆盖方法的死代码方面变得更加激进。使用下面描述的托管覆盖可以在 Sencha Cmd 中提供此优化,一旦在 Sencha Cmd 中可用。
以下是覆盖的标准形式。命名空间的选择有点武断,但请参阅下面的建议。
Ext.define('MyApp.patches.grid.Panel', {
override: 'Ext.grid.Panel',
...
});
通过使用 Ext.define
来管理覆盖,新的惯用法已经开放并正在积极利用。例如,在 Sencha Architect 的代码生成器中,以及在框架内部,将大型类(如 Ext.Element
)分解成更易于管理和内聚的部分。
覆盖作为补丁是历史用例,因此是当今实践中最常见的用例。
注意: 修补代码时要小心。虽然支持使用覆盖本身,但不支持覆盖框架方法的最终结果。每当升级到新的框架版本时,都应仔细检查所有覆盖。
也就是说,有时有必要覆盖框架方法。在这种情况下,标准覆盖形式是理想的。事实上,Sencha 支持有时会以这种形式为客户提供补丁。但是,一旦提供,管理此类补丁并在不再需要时删除它们,就是前面提到的审查过程的问题。
将补丁组织在与目标顶层命名空间关联的命名空间中。例如,“MyApp.patches”针对“Ext”命名空间。如果涉及第三方代码,则可能应该选择另一个级别或命名空间来对应其顶层命名空间。在此基础上,使用匹配的名称和子命名空间来命名覆盖。在前面的示例中
Ext -> MyApp.patches).grid.Panel
在处理代码生成(如在 Sencha Architect 中)时,一个类通常由两部分组成:一部分是机器生成的,另一部分是人工编辑的。在某些语言中,正式支持“部分类”或“两部分类”的概念。
使用覆盖,您可以对其进行干净地管理
在 ./foo/bar/Thing.js
中
Ext.define('Foo.bar.Thing', {
// NOTE: This class is generated - DO NOT EDIT...
requires: [
'Foo.bar.custom.Thing'
],
method: function () {
// some generated method
},
...
});
在 ./foo/bar/custom/Thing.js
中
Ext.define('Foo.bar.custom.Thing', {
override: 'Foo.bar.Thing',
method: function () {
this.callParent(); // calls generated method
...
},
...
});
命名建议
Foo.bar.ThingOverride
或 Foo.bar.ThingGenerated
,以便类的部分在列表中一起整理。面向对象设计中基类的常见问题是“臃肿的基类”。这是因为某些行为适用于所有类。但是,如果这些行为(或特性)不需要,如果它们作为某个大型基类的一部分实现,则无法轻易地将其移除。
使用覆盖,这些特性可以收集到它们自己的层次结构中,然后可以根据需要使用 requires
来选择这些特性。
在 ./foo/feature/Component.js
中
Ext.define('Foo.feature.Component', {
override: 'Ext.Component',
...
});
在 ./foo/feature/grid/Panel.js
中
Ext.define('Foo.feature.grid.Panel', {
override: 'Ext.grid.Panel',
requires: [
'Foo.feature.Component' // since overrides do not "extend" each other
],
...
});
现在可以通过要求来使用此特性
...
requires: [
'Foo.feature.grid.Panel'
]
或使用适当的“引导”文件(请参阅 Sencha Cmd 中的工作空间
...
requires: [
'Foo.feature.*'
]
命名建议
requires
和 uses
这些关键字在覆盖中受支持。使用 requires
可能会限制编译器对覆盖代码进行重新排序的能力。
callParent
和 callSuper
为了支持所有这些新的用例,Ext JS 4.0 和 Sencha Touch 2.0 中的 callParent
已增强为“调用下一个方法”。“下一个方法”可能是覆盖的方法或继承的方法。只要有下一个方法,callParent
就会调用它。
另一种查看方式是 callParent
对所有形式的 Ext.define
都起作用,无论是类还是覆盖。
虽然这在某些方面有所帮助,但不幸的是,它使得绕过原始方法(作为补丁或错误修复)变得更加困难。Ext JS 4.1 及更高版本和 Sencha Touch 2.1 及更高版本提供了一个名为 callSuper
的方法,该方法可以绕过覆盖的方法。
在将来的版本中,编译器将使用此语义差异来消除覆盖方法的死代码。
从 4.2.2 版本开始,覆盖可以根据框架版本或其他包的版本声明其 compatibility
。这对于有选择地应用补丁非常有用,当这些补丁与目标类版本不兼容时,可以安全地忽略它们。
最简单的用例是测试框架版本以进行兼容性检查
Ext.define('App.overrides.grid.Panel', {
override: 'Ext.grid.Panel',
compatibility: '4.2.2', // only if framework version is 4.2.2
//...
});
数组被视为 OR,因此如果任何规范匹配,则覆盖兼容。
Ext.define('App.overrides.some.Thing', {
override: 'Foo.some.Thing',
compatibility: [
'4.2.2',
'[email protected]'
],
//...
});
要要求所有规范都匹配,可以提供一个对象
Ext.define('App.overrides.some.Thing', {
override: 'Foo.some.Thing',
compatibility: {
and: [
'4.2.2',
'[email protected]'
]
},
//...
});
因为对象形式只是一个递归检查,所以这些对象可以嵌套
Ext.define('App.overrides.some.Thing', {
override: 'Foo.some.Thing',
compatibility: {
and: [
'4.2.2', // exactly version 4.2.2 of the framework *AND*
{
// either (or both) of these package specs:
or: [
'[email protected]',
'[email protected]+'
]
}
]
},
//...
});
有关版本语法的详细信息,请参阅 Ext.Version
的 checkVersion
方法。
随着 Sencha Cmd 的不断发展,它不断引入新的诊断消息,以帮助指出与这些准则的偏差。
一个好的开始是了解此信息如何帮助告知您自己的内部代码样式指南和实践。