类系统

概览

Ext JS 附带几百个类。迄今为止我们有超过200万开发者并且他们来自不同的背景和地点。 在如此规模下提供公共代码架构,我们面对一个巨大的挑战是:

  • 熟悉且简单易学
  • 快速开发,易于调试,无痛部署
  • 有组织的,可扩展性和可维护性

由于JavaScript是一种没有类的,面向原型的语言,它最强大的功能之一是灵活性。对任何问题使用许多不同的编码风格和技巧有多种解决方案。 然而,这种导致不可预知的成本。如果没有一个统一的结构,JavaScript代码可能很难理解, 维护和复用。

基于类的编程,在另一方面,仍然是面向对象编程最流行的模式。基于类的语言 通常需要强类型,封装,和标准编码约定。随着时间的推移,通过使开发者坚持一套大的原则,代码是更可能可预测的, 可扩展的, 可度量的。然而,这种模式不具备JavaScript的动态能力。

每种方法都有其优点和缺点,但是我们能否保留好的部件的同时把坏的部件隐藏起来吗?答案是能的,你可以用Ext JS 找到解决方案。

命名约定

使用一致的命名约定来贯穿你的整个代码库类、名字空间和文件命名,有助于保持你的代码有组织行性,结构化和可读性。

类名只包含字字母数字 字符。允许用数字但不建议使用,除非它们属于一个技术术语。不要使用下划线,连字号,或其他任何非字母数字字符。例如:

  • MyCompany.useful_util.Debug_Toolbar 不鼓励用
  • MyCompany.util.Base64 最好这样用

在使用对象的属性点(.)时,使用正确的命名空间,类名应该被组合成包。至少,应该有一个唯一的顶层名字空间后跟类名。例如:

MyCompany.data.CoolProxy
MyCompany.Application

顶层命名空间和实际的类名应该用驼峰命名法。其他都应该小写。例如:

MyCompany.form.action.AutoLoad

其他不是由Sencha发布的的类,都不能使用Ext 作为顶层命名空间。

首字母缩略词也应该遵循上面列出驼峰命名约定。例如:

  • Ext.data.JsonProxy 代替 Ext.data.JSONProxy
  • MyCompany.util.HtmlParser 代替 MyCompary.parser.HTMLParser
  • MyCompany.server.Http 代替 MyCompany.server.HTTP

源文件

类的名称直接映射到它们所存储的文件路径。其结果是,必须只有每个文件一个类。例如:

  • Ext.util.Observable 存放在 path/to/src/Ext/util/Observable.js
  • Ext.form.action.Submit 存放在 path/to/src/Ext/form/action/Submit.js
  • MyCompany.chart.axis.Numeric 存放在 path/to/src/MyCompany/chart/axis/Numeric.js

path/to/src 是你的应用程序类的目录。所有的类应该放到这个共同的根目录并且可以适当命名空间的来获得最佳开发,维护和部署经验。

方法和变量

  • 以类似的方式对类名,方法和变量名可以仅包含字母数字字符串。 允许用数字但不建议使用,除非它们属于一个技术术语。不要使用下划线,连字号,或其他任何非字母数字字符。
  • 方法和变量名应该总是使用驼峰命名法。这也适用于缩略词。

例子

  • 合理的方法名:

    • encodeUsingMd5()
    • getHtml() 代替 getHTML()
    • getJsonResponse() 代替 getJSONResponse()
    • parseXmlContent() 代替 parseXMLContent()
  • 合理的变量名:

    • var isGoodName
    • var base64Encoder
    • var xmlReader
    • var httpServer

属性

  • 类属性命名应当遵循同样的命名约定,除非它们是静态常量。

  • 静态类属性应当全部大写。例如:

    • Ext.MessageBox.YES = "Yes"
    • Ext.MessageBox.NO = "No"
    • MyCompany.alien.Math.PI = "4.13"

声明

你可以使用类创建一个方法: Ext.define。它的基本语法如下:

Ext.define(className, members, onClassCreated);
  • className:类名
  • members 是代表类成员的键 - 值对的集合对象
  • onClassCreated 当所定义的类的所有依赖都准备好被调用和类本身是完全创建一个可选的回调函数。由于类创建的异步特性,这个回调可以在许多情况下非常有用。这些都将进一步在第四节进行讨论

Example:

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 bob = Ext.create('My.sample.Person', 'Bob');

bob.eat("Salad"); // alert("Bob is eating: Salad");

注意: 我们创建了一个新的实例 My.sample.Person 使用 Ext.create() 方法。我们可以使用 new 关键字 (new My.sample.Person())。不过,推荐习惯使用 Ext.create 自从它允许你利用动态加载的优势。 有关动态加载的更多信息请参阅 快速入门指南

配置(config)

另外,在类创建之前,有个会被强大的 Ext.Class 预处理器预先处理的 config 属性。其特点包括:

  • 和其它其他类成员不一样,配置项完全被包裹封装在一起
  • 如果没有显式定义getter和setter方法,类创建过程中会对每个配置属性自动生成getter和setter方法,并添加到到类的原型(prototype)中。
  • 自动生成的setter方法会在set值之前调用apply方法(如果类中定义了此方法)。如果您需要在set值之前执行自定义逻辑,您可以覆盖这个配置项的apply方法。 如果您的apply方法无返回值,setter方法将不会给这个配置项set值。当配置项被set了一个与原先不一样的值,update方法(如果类中定义了)也将被调用。 新值和旧值都会作为参数,传递进apply和update方法。

对于 Ext 类使用这些配置,没必要手动调用 initConfig() 。 然而,对于你自己写的,继承自自 Ext.Base 的类,仍旧需要调用 initConfig()

你可以看到下面的配置实例。

Ext.define('My.own.Window', {
   extend: 'Ext.Component',
   /** @readonly */
   isWindow: true,

   config: {
       title: 'Title Here',

       bottomBar: {
           height: 50,
           resizable: false
       }
   },

   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) {
           if (!this.bottomBar) {
               return Ext.create('My.own.WindowBottomBar', bottomBar);
           }
           else {
               this.bottomBar.setConfig(bottomBar);
           }
       }
   }
});

/** A child component to complete the example. */
Ext.define('My.own.WindowBottomBar', {
   config: {
       height: undefined,
       resizable: true
   }
});

这里是如何使用它的例子:

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

alert(myWindow.getBottomBar().getHeight()); // alerts 100

静态

静态成员可以使用 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
    }
});

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"

错误处理和调试

Ext JS的有一些很有用的功能,可以帮助你调试和处理错误。

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

    throw new Error('['+ Ext.getDisplayName(arguments.callee) +'] Some message here');
  • 当使用 Ext.define() 定义任何类的任何方法时抛出错误,你应该看到的方法和类的名称调用堆栈,如果您使用的是基于WebKit的浏览器(Chrome或Safari)。例如,在Chrome中它会是什么样子:

Last updated