[翻译]Ext JS 教程-类系统 原

<h3>类系统</h3> <p>ExtJS 史上第一次进行了重整新的类系统的大重构。新的架构以ExtJS 4.X所编写的每一个类作为后盾,因此在你编写代码以前理解它是非常重要的。</p> <p>这个手册主要面向任何想在ExtJS 4.x中新建或者扩展类的开发人员。它分成四个部分:</p> <p>Ø 部分一:“综观”解释了稳定的类系统的需求</p> <p>Ø 部分二:“命名规则”讨论给类、方法、属性、变量和文件命名的最佳实践</p> <p>Ø 部分三:“动手实践”提供详细的一步步编码的例子</p> <p>Ø 部分四:“错误处理&amp;调试”提供如何处理一场的小建议和小计谋</p> <h3>一 综观</h3> <p>ExtJS 4 靠超过300 多个类驱动。我们拥有一个超过20万来自世界各地,具备各种编程背景的开发人员组成的巨大社区。在一个框架的范围内,我们面对提供一个通用的编码结构的那些大挑战:</p> <p>Ø 简单易上手</p> <p>Ø 开发快速、调试简单、部署无忧</p> <p>Ø 结构良好,可扩展可维护</p> <p>JavaScript 是 classless 的面向原型的语言。天性使然,灵活是这个语言最强大的特性。使用不同的方式,不同的编码形式和技术,都可以让工作有效。然而就是那个特性,带来了不可预知的代价。没有一个统一的形式,JavaScript代码可能很难去理解、维护和重用。</p> <p>从另一方面来看,基于类的编程仍然是面向对象编程领域最受欢迎的模式。基于类的语言常常需要强类型,提供封装和标准的编码规范。一般而言要让开发人员遵守一大堆规则,而编码就会变得一直可预知、可扩展和规规矩矩。然而,他们不会有在JavaScript这样的语言中发现的同样的动态能力。</p> <p>每种方法都有其利弊,但是我们是否可以利用两者好处的同时避免他们的坏处呢?答案是肯定的,我们在ExtJS 4中实现了这个解决方案。</p> <h4>二 命名规范</h4> <p>至始至终为你编码的类、命名空间和文件名使用一致的命名规则有助于保持你代码的组织性、结构性和可读性。</p> <h4>1)类</h4> <p>类名应该只包含字母和数字字符。数字在大多数情况下是不鼓励使用的,除非他们属于一种技术手段。不要使用下划线,连字符或者其它任何非字母非数字的字符。举个例子:</p> <p>Ø MyCompany.useful_util.Debug_Toolbar 不鼓励这样命名</p> <p>Ø MyCompany.util.Base64 是可以被接受的</p> <p>类名应该被组成成为包,在包中合适恰当的使用对象属性点记号(.)分出命名空间。至少,应该只有唯一的顶层命名空间后面跟类名。举个例子:</p> <p>MyCompany.data.CoolProxy</p> <p>MyCompany.Application</p> <p>顶层命名空间和真实类的命名应该采用Camel形式(单词的首字母都大写),其它所有事物都应该是小写的。举个例子:</p> <p>MyCompany.form.action.AutoLoad</p> <p>不是Sencha发行的类永远不应该使用Ext作为顶层命名空间的名字。</p> <p>首字母缩略词也应该遵守上面列出的Camel形似命名规则。示例如下:</p> <p>Ext.data.JsonProxy 而不是Ext.data.JSONProxy</p> <p>MyCompany.util.HtmlParser 而不是 MyCompary.parser.HTMLParser</p> <p>MyCompany.server.Http 而不是MyCompany.server.HTTP</p> <h4>2)源代码</h4> <p>类地址的名字应该直接指向文件被存储的路径。基于此,每个文件中只能有一个类,示例如下:</p> <p>Ext.util.Observable 被存储在路径 /to/src/Ext/util/Observable.js 中</p> <p>Ext.form.action.Submit 被存储在路径 /to/src/Ext/form/action/Submit.js中</p> <p>MyCompany.chart.axis.Numeric 被存储在路径 /to/src/MyCompany/chart/axis/Numeric.js中</p> <p>Path/to/src 是你的应用程序类所在的路径。所有的类都应该在这个公共的根下面,并且为了获得最好的开发、维护和部署体验,适当的赋予命名空间。</p> <p>2)方法和变量</p> <p>跟类名类似,方法和变量的名字应该只包含数字和字母字符。数字被允许的,但在大多数情况下是不被鼓励的,除非是属于某种技术手段。不要使用下划线、连字符,或者任何其它非字母和数字的字符。</p> <p>方法和变量名字应该一直使用camel形式(第一个单词首字母小写,接下来的单词首字母都大写)。这也同样适用于首字母缩略词。</p> <p>示例:</p> <p>可以被接受的方法名字:encodeUsingMd5() getHtml() instead of getHTML() getJsonResponse() 而不是:getJSONResponse() parseXmlContent() instead ofparseXMLContent()</p> <p>可以被接受的变量名称: var isGoodName var base64Encoder var xmlReader var httpServer</p> <h5>3)属性</h5> <p>类属性的命名规则同上述方法和变量的命名规则是完全一样的,除开它们是静态常量的情况。</p> <p>静态常量类属性应该都是大写的。示例如下:</p> <p>Ext.MessageBox.YES = &quot;Yes&quot;</p> <p>Ext.MessageBox.NO = &quot;No&quot;</p> <p>MyCompany.alien.Math.PI = &quot;4.13&quot;</p> <h4>三 动手实践</h4> <h5>1. 声明</h5> <p><b>1.1</b><b>)老方法</b></p> <p>如果你使用过任何ExtJS的老版本,你一定熟悉使用 Ext.extend 去创建一个类:</p> <p>var MyWindow = Ext.extend(Object, { ... });</p> <p>这种方法很容易用来去创建一个继承另外一个类的新类。然而不像其它方式的继承,我们没有流畅的创建类的其它方面的API,比如配置,静态性和混合。我们很快将会重新详细的了解这些东西。</p> <p>让我们看一下另外一个例子:</p> <p>My.cool.Window = Ext.extend(Ext.Window, { ... });</p> <p>在这个例子中我们给新类带上了命名空间,并且让它继承了 Ext.Window。这里我们需要专注于两个概念:</p> <p>1. My.cool 需要在我们把 Window 当作它的属性前,是一个存在的对象</p> <p>2. Ext.Window 在它能被引用前需要存在或者已经被加载进来</p> <p>第一条常常使用 Ext.namespace(用 Ext.ns作别名)来解决。 这个方法横向递归对象/属性树,并在他们还不存在时创建之。 烦人的地方在于,你需要一直牢记把它们加在 Ext.extend 之上。</p> <p>Ext.ns('My.cool');</p> <p>My.cool.Window = Ext.extend(Ext.Window, { ... });</p> <p>第二条专注起来不是很容易,因为 Ext.window 也许依赖于其它直接或间接继承的类,并且这样轮转下去,这些依赖也依赖于其它类的存在。由于那个原因,编写应用程序之前ExtJS 4 常常要包含包括了整个库的 ext-all.js ,即使他们也许仅仅只需要这个框架的一小部分。</p> <p><b>1.2</b><b>)新方法</b></p> <p>ExtJS 4 仅仅使用一个方法排除了所有那些缺点。你仅需要记住如何创建类: Ext.define。它的简单语法是像下面这样:</p> <p>Ext.define(className, members, onClassCreated);</p> <p>className:类的名字</p> <p>Members 代表一个类成员的键值对集合的对象</p> <p>onClassCreated 是一个在类的所有依赖都已经准备好时回掉执行的可选方法,同时这个类本身完全创建了。归功于新的创建类的异步形式,这种会掉在很多情况下都会很有用。这将在第四部分讨论到。</p> <p>示例:</p> <p>Ext.define('My.sample.Person', {</p> <p>name: 'Unknown',</p> <p>constructor: function(name) {</p> <p>if (name) {</p> <p>this.name = name;</p> <p>}</p> <p>},</p> <p>eat: function(foodType) {</p> <p>alert(this.name + &quot; is eating: &quot; + foodType);</p> <p>}</p> <p>});</p> <p>var aaron = Ext.create('My.sample.Person', 'Aaron');</p> <p>aaron.eat(&quot;Salad&quot;); // alert(&quot;Aaron is eating: Salad&quot;);</p> <p>注意我们用 Ext.create() 方法创建了一个 My.sample.Person 的新实体。我们可能使用新的关键字(My.name.Person())。然而建议你形成一直使用 Ext.create 的习惯,因为它允许你利用动态加载的好处。更多关于动态加载的内容见入门指南。</p> <h5>2. 配置</h5> <p>在 ExtJS 4种,我们推出专注的 config 属性,它在类被创建以前通过强大的 Ext.Class 前处理器获得处理。特性包括:</p> <p>对于其它类成员来说配置是完全封装的。</p> <p>每一个配置属性的获取和设置方法将在类创建期间自动生成到类的原型中,如果这些方法还没有被定义。</p> <p>一个apply方法也为每一个配置属性生成了。自动生成的设置器方法在设置值之前内部调用apply方法。如果你需要在设值之前运行一些定制逻辑,重写config属性的apply方法,如果apply没有返回值,那么设置器将不会设值。示例见下面的 applyTitle.</p> <p>这是一个示例:</p> <p>Ext.define('My.own.Window', {</p> <p>/** @readonly */</p> <p>isWindow: true,</p> <p>config: {</p> <p>title: 'Title Here',</p> <p>bottomBar: {</p> <p>height: 50,</p> <p>resizable: false</p> <p>}</p> <p>},</p> <p>constructor: function(config) {</p> <p>this.initConfig(config);</p> <p>},</p> <p>applyTitle: function(title) {</p> <p>if (!Ext.isString(title) || title.length === 0) {</p> <p>alert('Error: Title must be a valid non-empty string');</p> <p>}</p> <p>else {</p> <p>return title;</p> <p>}</p> <p>},</p> <p>applyBottomBar: function(bottomBar) {</p> <p>if (bottomBar) {</p> <p>if (!this.bottomBar) {</p> <p>return Ext.create('My.own.WindowBottomBar', bottomBar);</p> <p>}</p> <p>else {</p> <p>this.bottomBar.setConfig(bottomBar);</p> <p>}</p> <p>}</p> <p>}</p> <p>});</p> <p>/** A child component to complete the example. */</p> <p>Ext.define('My.own.WindowBottomBar', {</p> <p>config: {</p> <p>height: undefined,</p> <p>resizable: true</p> <p>}</p> <p>});</p> <p>而下面是一个它是如何被使用的例子:</p> <p>var myWindow = Ext.create('My.own.Window', {</p> <p>title: 'Hello World',</p> <p>bottomBar: {</p> <p>height: 60</p> <p>}</p> <p>});</p> <p>alert(myWindow.getTitle()); // alerts &quot;Hello World&quot;</p> <p>myWindow.setTitle('Something New');</p> <p>alert(myWindow.getTitle()); // alerts &quot;Something New&quot;</p> <p>myWindow.setTitle(null); // alerts &quot;Error: Title must be a valid non-empty string&quot;</p> <p>myWindow.setBottomBar({ height: 100 });</p> <p>alert(myWindow.getBottomBar().getHeight()); // alerts 100</p> <h5>3. 静态成员</h5> <p>静态成员可以使用 statics 配置被定义。</p> <p>Ext.define('Computer', {</p> <p>statics: {</p> <p>instanceCount: 0,</p> <p>factory: function(brand) {</p> <p>// 'this' in static methods refer to the class itself</p> <p>return new this({brand: brand});</p> <p>}</p> <p>},</p> <p>config: {</p> <p>brand: null</p> <p>},</p> <p>constructor: function(config) {</p> <p>this.initConfig(config);</p> <p>// the 'self' property of an instance refers to its class</p> <p>this.self.instanceCount ++;</p> <p>}</p> <p>});</p> <p>var dellComputer = Computer.factory('Dell');</p> <p>var appleComputer = Computer.factory('Mac');</p> <p>alert(appleComputer.getBrand()); // using the auto-generated getter to get the value of a config property. Alerts &quot;Mac&quot;</p> <p>alert(Computer.instanceCount); // Alerts &quot;2&quot;</p> <h4>四 错误处理和调试</h4> <p>ExtJS 4 包含一些能在调试和错误处理工作上帮助你的有用特性。</p> <p>你可以使用 Ext.getDisplayName() 去得到任何方法名字的显示。这在抛出错误时在错误描述信息中显示类名和方法名,特别有用。</p> <p>throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');</p> <p>如果一个错误在任何使用 Ext.define() 定义的类的任何方法中被抛出, 你应该使用一个基于 Webkit 内核的浏览器(Chrome 或者 Safari)去观察调用堆栈中方法和类的名字。例如,下面是它如何在Chrome中显示:</p> <p><a href="http://static.oschina.net/uploads/img/201305/30194951_odHt.jpg"><img title="clip_image002" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="clip_image002" src="http://static.oschina.net/uploads/img/201305/30194954_EM97.jpg" width="740" height="520" /></a></p> <h4>还要看看</h4> <p>· <u><a href="http://www.sencha.com/blog/countdown-to-ext-js-4-dynamic-loading-and-new-class-system">Dynamic Loading and the New Class System</a></u></p> <p>· <u><a href="http://edspencer.net/2011/01/classes-in-ext-js-4-under-the-hood.html">Classes in Ext JS 4: Under the Hood</a></u></p> <p>· <u><a href="http://edspencer.net/2011/01/ext-js-4-the-class-definition-pipeline.html">The Class Definition Pipeline</a></u></p>

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏从流域到海域

《Java程序设计基础》 第4章手记

《Java程序设计基础》 第4章手记 本章主要内容 - 语句和复合语句 - 分支结构 - 循环结构 - 跳转语句 这四部...

21380
来自专栏walterlv - 吕毅的博客

使用 ExceptionDispatchInfo 捕捉并重新抛出异常

发布于 2017-10-23 14:22 更新于 2017-10...

10810
来自专栏互扯程序

设计模式不止23种!

现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

14340
来自专栏闰土大叔

闰土说JS进阶之作用域链

前言 在前端应聘中,相信会有不少面试官都会问你,说说你理解的js作用域,或者作用域链。显然,这是一道经典的js面试题,对于老司机而言可谓是小菜一碟,而对于前端...

35090
来自专栏代码世界

计算机基础,Python基础--变量以及简单的循环

一、计算机基础 1.CPU   相当于人体的大脑,用于计算处理数据。 2.内存    用于存储数据,CPU从内存调用数据处理计算,运算速度很快。 PS:问:...

29070
来自专栏偏前端工程师的驿站

JS魔法堂:不完全国际化&本地化手册 之 实战篇

前言  最近加入到新项目组负责前端技术预研和选型,其中涉及到一个熟悉又陌生的需求——国际化&本地化。熟悉的是之前的项目也玩过,陌生的是之前的实现仅仅停留在"有"...

315100
来自专栏Java爬坑系列

【JAVA零基础入门系列】Day14 Java对象的克隆

  今天要介绍一个概念,对象的克隆。本篇有一定难度,请先做好心理准备。看不懂的话可以多看两遍,还是不懂的话,可以在下方留言,我会看情况进行修改和补充。   克隆...

23160
来自专栏听雨堂

【4】通过简化的正则表达式处理字符串

阅读目录 常见字符串操作 使用正则表达式处理字符串 “前后限定”查找目标 自动处理转义字符 界定串的通用化 多个目标的匹配 进一步扩展 结论 在...

26660
来自专栏CDA数据分析师

教你一招:用 50 行 Python 代码制作一个计算器

简介 在这篇文章中,我将向大家演示怎样向一个通用计算器一样解析并计算一个四则运算表达式。当我们结束的时候,我们将得到一个可以处理诸如 1+2*-(-3+2)/5...

23670
来自专栏斑斓

Scala的面向对象与函数编程

很难说FP和OO孰优孰劣,应该依场景合理选择使用。倘若从这个角度出发,Scala就体现出好处了,毕竟它同时支持了OO和FP两种设计范式。 从设计角度看,我认为O...

32250

扫码关注云+社区

领取腾讯云代金券