ajax|web|程式|進階 下載本文原始碼
一、 引言
在第一部分中,我們討論了AJAX基礎——建立從指令碼到伺服器的通訊的能力,這正是使HTML頁面具有動態能力的原因所在。然而,這就意味著我們已準備好拋棄我們自己版本的Yahoo郵件嗎?不,還沒有。原因在於:AJAX是一個混合的祝福。一方面,它使我們能夠在Web上建立豐富的案頭級的應用程式;另一方面,如果我們把"翻頁面式"的Web應用程式與用戶端/伺服器或Swing版本的程式進行比較,那麼會看到其開發實踐並不很相同。我們將需要習慣於這樣的事實:構建一個豐富的UI需要時間。須知,允許使用者實現更大的靈活性也就相應地需要付出更多的時間為代價。
最後的答案當然要依賴於大量的組件庫、架構以及具有工業力量的開發工具。且不考慮工具,本文集中於討論在今天對於AJAX熱心者有哪些技術是可用的。在強調需要構建可重用的商業組件的同時,本文將重點分析"隱含的"JavaScript中的物件導向的力量。另外,在強調需要構建定製的UI組件的同時,本文將介紹一個簡便的方法——用定製的用戶端HTML標籤來封裝描述邏輯。
二、 AJAX語言——對象面向的JavaScript
由定義來看,JavaScript是典型的AJAX語言。不同於Java,JavaScript並不強調OO風格的編碼。然而,令人吃驚的是JavaScript居然全面支援所有的OO語言的主要屬性:封裝、繼承和多態性。Douglas Crockford甚至稱JavaScript是"世界上最易被誤解的程式設計語言"。讓我們回顧一下JavaScript的物件導向的地方吧。
資料類型
在Java中,一個類定義了一個資料和它的相關行為的組合。儘管JavaScript保留了class關鍵字,但是它不支援與常規OOP語言一樣的語義。
這聽起來可能覺得奇怪,但是在JavaScript中,對象是用函數來定義的。事實上,通過在下面的樣本中定義一個函數,你就定義了一個簡單的空類Calculator:
一個新的執行個體的建立與在Java中相同-使用new操作符:
var myCalculator = new Calculator(); |
上面這個函數不僅定義一個類,而且還擔當了一個構造器。在此,操作符new實現了這一魔術-執行個體化一個類Calculator的對象並且返回一個對象參考而不是只調用該函數。
建立這樣的空類是沒錯,但在實際中並沒有多大用處。下面,我們準備使用一個Java-指令碼原型結構來填充類定義。JavaScript使用原型當作建立對象的模板。所有的原型屬性和方法被參考引用地複製到一個類的每個對象中,所以它們都具有相同的值。你可以改變一個對象中的原型屬性的值,並且該新值會覆蓋從原型中複製過來的預設值,但是這僅對於在一個執行個體中。下列語句將把一個新屬性添加到Calculator對象的原型上:
Calculator.prototype._prop = 0; |
既然JavaScript並沒有提供一個方法來從句法上表示一個類定義,那麼我們將使用with語句來標記該類的定義邊界。這也將使得範例程式碼更為短小,因為該with語句被允許在一個指定的對象上執行一系列的語句而不需要限制屬性。
function Calculator() {}; with (Calculator) { prototype._prop = 0; prototype.setProp = function(p) {_prop = p}; prototype.getProp = function() {return _prop}; } |
到目前為止,我們定義了並且初始化了公開變數_prop,並且為它提供了getter和setter方法。
需要定義一個靜態變數?你可以把靜態變數當作是為類所擁有的一個變數。因為在JavaScript中的類用函數對象來描述,所以我們只需要把一個新屬性添加到該函數上:
現在,既然這個iCount變數是一個Calculator對象的屬性,那麼它將會被類Calculator的所有執行個體所共用。
function Calculator() {Calculator.iCount++;}; |
上面的代碼計算類Calculator的所有執行個體的個數。
封裝
通過使用如上面所定義的"Calculator",我們可以存取所有的"class"資料;然而,這增加了衍生類別中命名衝突的危險性。我們明顯地需要封裝以把對象看作自包含的實體。
資料封裝的一種標準語言機制是使用私人變數。並且一個常用的仿效一個私人變數的JavaScript技術是在構造器中定義一個局部變數;這樣以來,該局部變數的存取只能經由getter和setter來實現-它們是該構造器中的內建函式。在下列執行個體中,_prop變數在Calculator函數中定義並且在函數範圍外不可見。其中有兩個匿名的內建函式(分別被賦予setProp和getProp屬性)讓我們存取"私人"變數。另外,請注意,這裡this的使用-十分相似於在Java中的用法:
function Calculator() { var _prop = 0; this.setProp = function (p){_prop = p}; this.getProp = function() {return _prop}; }; |
常常被忽視的是在JavaScript中作如此封裝所付出的代價。須知,這種代價可能是巨大的,因為內建函式對象對於該"class"的每一個執行個體被不斷地重複建立。
因此,既然基於原型構建對象速度更快並且消費更少些的記憶體,那麼我們在最強調效能的場所特別支援使用公用的變數。請注意,你可以使用命名慣例來避免名稱衝突-例如,在公用的變數的前面加上該類名。
[1] [2] [3] [4] 下一頁