ExtJS 4 類系統

ExtJS 4的類系統(class system)進行了一次重大重構,ExtJS4的新架構就是基於這套新的類系統構建的,所以有必要先了解如下這個class system
這篇文章分爲四章 chrome

  • I: 「Overview」 解釋健壯類系統的重要性
  • II: 「Naming Conventions」 最佳命名規範實踐(實際上是要求必須遵守它的規範)
  • III: 「Hands-on」 詳細的例子
  • IV: 「Errors Handling & Debugging」 一些處理問題的實用提示

I. Overview 概覽

ExtJS 4 有300多個類,社區裏有20w+不一樣背景的開發者,提供一個好的代碼架構是個巨大的挑戰: 編程

  • 易學,學習成本低
  • 快速開發,容易調試和發佈
  • 組織良好,可擴展可維護

JavaScript是個基於原型鏈繼承的語言,沒有類的概念。並且JavaScript語言特色就是鬆散和自由,實現一個一樣的功能,能夠有不少種方式,可是若是聽任它的鬆散和自由,就很難維護和重用代碼。
面向對象編程絕大部分都是基於類的。基於類的編程語言一般須要強類型,提供代碼封裝,而且有標準的編碼習慣,說了一堆廢話,不翻譯了,總結如下就是能作到既有面向對象編程的規範性,又能作到JavaScript的靈活性 架構

II. Naming Conventions 命名規範

命名規範,使用一致的命名規範可讓你的代碼結構清晰,可讀性強。 app

1. Classes 類

類名只能包含字母數字,不推薦使用數字,除非是經常使用詞。不要用下劃線中化纖等非字母數字字符。 異步

  • MyCompany.useful_util.Debug_Toolbar 不合法
  • MyCompany.util.Base64 合法

應該組織在或者說命名空間下面,而且至少要有一個頂層命名空間,例如:編程語言

 
MyCompany.data.CoolProxy
MyCompany.Application

頂層命名空間和真正的類,應該採用駝峯式命名,其餘一概小寫,例如:函數

MyCompany.form.action.AutoLoad

非Ext官方類,不能夠在Ext頂層命名空間下(這是爲了防止衝突)
首字母組合詞也要採用駝峯式命名,例如: 學習

  • Ext.data.JsonProxy 而不是 Ext.data.JSONProxy
  • MyCompany.util.HtmlParser 而不是 MyCompary.parser.HTMLParser
  • MyCompany.server.Http 而不是 MyCompany.server.HTTP

2. Source Files 源文件

類的命名和源文件存放路徑是對應的,例如: this

  • 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就是程序跟目錄下的那個app目錄,全部類都應該這樣組織,保證維護性 編碼

3. Methods and Variables 方法和成員變量

  • 和類名同樣只能用字母和數字,其餘符號不能夠
  • 一樣是駝峯命名,可是首字母小寫,首字母組合詞也如此

例如:

  • 合法的方法名:encodeUsingMd5(),getHtml()代替getHTML(),getJsonResponse()代替getJSONResponse(),parseXmlContent()代替parseXMLContent()
  • 合法的變量名:var isGoodName;, var base64Encoder, var xmlReader, var httpServer

4. Properties 屬性

  • 跟成員變量一致
  • 若是是常量
Ext.MessageBox.YES = "Yes"
Ext.MessageBox.NO = "No"
MyCompany.alien.Math.PI = "4.13"

III. Hands-on 實踐一下

1. Declaration 聲明

1.1 老的方式

若是你使用過ExtJS 3或者以前的版本,可能會熟悉Ext.extend,能夠用來建立一個類

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

這個方法很容易就能夠聲明一個類並繼承自另外一個類,可是也有缺陷

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

這個例子中咱們須要把類定義在命名空間裏,並繼承自Ext.Window類,可是有兩個問題:

  1. My.cool必須以前定義過,這個命名空間必須已經存在
  2. Ext.Window必須已經加載

第一條一般可使用Ext.namespace(同Ext.ns)解決,這個方法會把不存在的命名空間都建立出來,無聊的是你必須記得在Ext.extend以前加上這句話

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

第二個問題,ExtJS4之前的版本都很差解決依賴問題,所以一般是引入ext-all.js

1.2 新的方式

ExtJS 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");

注意這裏建立一個新的My.sample.Person實例使用的是Ext.create()方法,使用new關鍵字也能夠建立實例(new My.sample.Person()),可是不推薦使用new,應該養成使用Ext.create的習慣,由於這樣能夠利用到動態加載的好處,有關動態加載能夠參看個人另一篇教程 ExtJS 4 入門

2. Configuration 配置(實例成員)

ExtJS 4 中引入了一個專用的config屬性,這個屬性在類建立以前,會被Ext.Class預先處理,並有一下特性:

  • 配置項被封裝起來,和類的其餘屬性方法不混雜在一塊兒了
  • 自動生成了屬性的getter和setter
  • 自動生成了一個apply方法,apply方法在setter以前調用,能夠經過apply方法定製setter的行爲,若是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 靜態成員

靜態成員經過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"

IV. Errors Handling & Debugging 錯誤處理和調試

ExtJS 4 引入了不少有用的特性幫助調試和錯誤處理

可使用Ext.getDisplayName()得到函數名稱,例如

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

在用Ext.define()定義出來的類中拋出(throw)錯誤(error),能夠在safari或者chrome的控制檯中看到方法名和類名和調用棧

調用棧

相關文章
相關標籤/搜索