Class System

  • Class names may only contain alphanumeric characters.
  • Class names should be grouped into packages where appropriate and properly namespaced using object property dot-notation.



  • The top-level namespaces and the actual class names should be in CamelCased, everything else should be all lower-cased


  • Classes that are not distributed by Sencha should never use Ext as the top-level namespace.

  • Acronyms should also follow CamelCased convention listed above

    Ext.data.JsonProxy instead of Ext.data.JSONProxy

  • As a result, there must only be one class per file.

  • Static class properties that are constants should be all upper-cased.

    Ext.MessageBox.YES = "Yes"

    Ext.MessageBox.NO = "No"

    MyCompany.alien.Math.PI = "4.13"




// we didn't have a fluent API for other aspects of class creation, such as configuration, statics and mixins. 
// We will be reviewing these items in details shortly.
var MyWindow = Ext.extend(Object, { ... });


// 不能更好得使用动态加载带来的性能提升
My.cool.Window = Ext.extend(Ext.Window, { ... });


Ext.define(className, members, onClassCreated);
  • className: The class name
  • members is an object represents a collection of class members in key-value pairs
  • onClassCreated is an optional function callback to be invoked when all dependencies of this class are ready, and the class itself is fully created. Due to the new asynchronous nature of class creation, this callback can be useful in many situations.

This is an example:

Ext.define('My.sample.Person', {

    name: 'Unknown',
    constructor: function(name) {
        if (name) {
            this.name = name;

        return this;

    eat: function(foodType) {
        alert(this.name + " is eating: " + foodType);

        return this;

// 使用构造方法创建类
var aaron = Ext.create('My.sample.Person', 'Aaron');
aaron.eat("Salad"); // alert("Aaron is eating: Salad");


new My.sample.Person()        



Ext.create('widget.useredit'); 等价于 Ext.widget('useredit');


  • Configurations are completely encapsulated from other class members
  • Getter and setter, methods for every config property are automatically generated into the class’ prototype during class creation if the class does not have these methods already defined.
  • An apply method is also generated for every config property. The auto-generated setter method calls the apply method internally before setting the value. Override the apply method for a config property if you need to run custom logic before setting the value. If apply does not return a value then the setter will not set the value. For an example see applyTitle below.


Here’s an example:

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

    config: {
        title: 'Title Here',

        bottomBar: {
            enabled: true,
            height: 50,
            resizable: false

    constructor: function(config) {

        return this;

    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 {

And here’s an example of how it can be used:

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






Ext.define('Sample.Musician', {
    extend: 'Sample.Person',
           mixins: {
        guitar: 'Sample.ability.CanPlayGuitar',
        compose: 'Sample.ability.CanComposeSongs',
        sing: 'Sample.ability.CanSing'

如果mixins中的方法和定义类的方法相同,则mixins中的方法被覆盖,但是可以通过mixins中的对象,如this.mixins.canSing.sing.call(this); 参考这里



Ext.define('Computer', {
    statics: {
        instanceCount: 0,
        factory: function(brand) {
            // 'this' in static methods refer to the class itself
            return new this({brand: brand});

    constructor: function(config) {

        // the **self** property of an instance refers to its class
        this.self.instanceCount ++;

var dellComputer = Computer.factory('Dell');
alert(Computer.instanceCount); // Alerts "2" 



listeners: {
    load: onFirstLoadData,
    single: true



Using callParent and callSuper

To support all of these new uses cases, callParent was enhanced in Ext JS 4.0 and Sencha Touch 2.0 to “call the next method”. The “next method” may be an overridden method or an inherited method. As long as there is a next method, callParent will call it.

Another way to view this is that callParent works the same for all forms of Ext.define, be they classes or overrides.

While this helped in some areas, it unfortunately made bypassing the original method (as a patch or bug fix) more difficult. So in Ext JS 4.1.1a, Ext JS 4.1.2a and Sencha Touch 2.1, there is now a method named callSuper that can be used to bypass an overridden method.

In future releases, the compiler will use this semantic difference to perform dead-code elimination of overridden methods.


  • 打补丁

    作为补丁时,命名规则如(Ext -> MyApp.patches).grid.Panel,表示重写Ext.grid.Panel,框架升级时,需要注意是否可以去除这些override。

  • 作为局部类

    When dealing with code generation (as in Sencha Architect), it is common for a class to consist of two parts: one machine generated and one human edited. In some languages, there is formal support for the notion of a “partial class” or a class-in-two-parts.

    Using an override, you can manage this cleanly:

    In ./foo/bar/Thing.js:

    Ext.define('Foo.bar.Thing', {
        // NOTE: This class is generated - DO NOT EDIT...
        requires: [
        method: function () {
            // some generated method

    In ./foo/bar/custom/Thing.js:

    Ext.define('Foo.bar.custom.Thing', {
        override: 'Foo.bar.Thing',
        method: function () {
            this.callParent(); // calls generated method

    Naming Recommendations:

    • Organize generated vs. hand-edited code by namespace.
    • If not by namespace, consider a common base name with a suffix on one or the other (e.g., “Foo.bar.ThingOverride” or “Foo.bar.ThingGenerated”) so that the parts of a class collate together in listings.

    • Overrides as Aspects

      A common problem for base classes in object-oriented designs is the “fat base class”. This happens because some behaviors apply across all classes. When these behaviors (or features) are not needed, however, they cannot be readily removed if they are implemented as part of some large base class.

      Using overrides, these features can be collected in their own hierarchy and then requires can be used to select these features when needed.

      In ./foo/feature/Component.js:

      Ext.define(‘Foo.feature.Component’, {

      override: 'Ext.Component',


      In ./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


      This feature can be used now by requiring it:

      requires: [



      Or with a proper “bootstrap” file (see Workspaces in Sencha Cmd or Single-Page Ext JS Apps)

      requires: [



      Naming Recommendation:

    • Organize generated vs. hand-edited code by namespace. This enables use of wildcards to bring in all aspects of the feature.