用AJAX開發智能Web應用程式之進階篇(1)

來源:互聯網
上載者:User
ajax|web|程式|進階

一、AJAX語言——對象面向的JavaScript

由定義來看,JavaScript是典型的AJAX語言。不同於Java,JavaScript並不強調OO風格的編碼。然而,令人吃驚的是JavaScript居然全面支援所有的OO語言的主要屬性:封裝、繼承和多態性。Douglas Crockford甚至稱JavaScript是"世界上最易被誤解的程式設計語言"。讓我們回顧一下JavaScript的物件導向的地方吧。

資料類型

在Java中,一個類定義了一個資料和它的相關行為的組合。儘管JavaScript保留了class關鍵字,但是它不支援與常規OOP語言一樣的語義。

這聽起來可能覺得奇怪,但是在JavaScript中,對象是用函數來定義的。事實上,通過在下面的樣本中定義一個函數,你就定義了一個簡單的空類Calculator:

function 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中的類用函數對象來描述,所以我們只需要把一個新屬性添加到該函數上:

Calculator.iCount=0;


現在,既然這個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"的每一個執行個體被不斷地重複建立。

因此,既然基於原型構建對象速度更快並且消費更少些的記憶體,那麼我們在最強調效能的場所特別支援使用公用的變數。請注意,你可以使用命名慣例來避免名稱衝突-例如,在公用的變數的前面加上該類名。繼承

乍看之下,JavaScript缺乏對類層次的支援,這很相似於物件導向語言的程式員對於現代語言的期盼。然而,儘管JavaScript句法沒有象Java一樣支援類繼承,但是我們仍然能夠在JavaScript中實現繼承-通過把已定義類的一個執行個體拷貝到其衍生類別的原型當中。

在我們提供舉例之前,我們需要介紹一個constructor屬性。JavaScript保證每一個原型中包含constructor-它擁有到該構造器函數的一個參考。換句話說,Calculator.prototype.constructor包含一個到Calculator()的參考。

現在,下面的代碼顯示了怎樣從基類Calculator衍生類別ArithmeticCalculator。其中,"第一行"取得類Calculator的所有的屬性,而"第二行"把原型constructor的值恢複成ArithmeticCalculator:

function ArithmeticCalculator() { };

with (ArithmeticCalculator) {

 ArithmeticCalculator .prototype = new Calculator();//第一行

 prototype.constructor = ArithmeticCalculator;//第二行

}

就算上面的執行個體看起來象一個合成體而不象是繼承,但是JavaScript引擎還是清楚這個原型鏈的。特別是,instanceof操作符會正確地適用於基類和衍生類別。假定你建立類ArithmeticCalculator的一個新執行個體:

var c = new ArithmeticCalculator;

運算式c instanceof Calculator和c instanceof ArithmeticCalculator都會成立。

注意,在上面樣本中的基類的constructor是在初始化ArithmeticCalculator原型時被調用的,而在建立衍生類別的執行個體時是不被調用的。這可能會帶來不想要的負面影響,而且為了實現初始化你應該考慮建立一個獨立的函數。由於該構造器並不是一個成員函數,所以它無法通過this參考引用調用。我們將需要一個能調用超類的"Calculator"成員函數:

function Calculator(ops) { ...};

with (Calculator) { prototype.Calculator=Calculator;}

現在,我們可以寫一個繼承類-它顯式地調用基類的構造器:

function ArithmeticCalculator(ops) { this.Calculator(ops);};

with (ArithmeticCalculator) {

 ArithmeticCalculator .prototype = new Calculator;

 prototype.constructor = ArithmeticCalculator;

 prototype.ArithmeticCalculator = ArithmeticCalculator;

}

多態性



JavaScript是一種非類型化的語言-在此,一切都是對象。因此,如果有兩個類A和B,它們都定義一個foo(),那麼JavaScript將允許在A和B的執行個體上多態地調用foo()-即使不存在層次關係(雖然是可實現的)。從這一角度來看,JavaScript提供一個比Java更寬的多態性。這種靈活性,象往常一樣,也要付出代價。在這種情況中,代價是把類型檢查工作代理到應用程式代碼。具體地說,如果需要檢查一個參考確實指向一個所希望的基類,那麼這可以通過instanceof操作符來實現。

另一方面,JavaScript並不檢查函數調用中的參數-這可以防止用一樣的命名和不同的參數來定義多態函數(並且讓編譯器選擇正確的簽名)。代之的是,JavaScript提供了一個Java 5風格的函數範圍內的argument對象-它允許你根據參數的類型和數量的不同而實現一個不同的行為。

二、 樣本展示

本文所附源碼列表1實現了一個計算機-它可以計算以一個逆向波蘭式標誌的運算式。該樣本展示了本文中所介紹的主要技術並且也介紹了一些獨特的JavaScript特性的用法,例如在一個動態函數調用中以一個數組元素的方式訪問對象屬性。

為了使列表1工作,我們需要另外準備一些代碼-它們用於執行個體化該計算機對象並且調用evaluate方法:

var e = new ArithmeticCalcuator([2,2,5,"add","mul"]);

alert(e.evaluate());

三、 AJAX組件授權

所有的AJAX組件授權方案在今天被邏輯地分成兩組。具體地說,第一組用於與基於HTML的UI定義的無縫整合。第二組把HTML當作一個UI定義語言以支援某種XML。在本文中,我們從第一組中來展示一種方法-雖然它存在於瀏覽器之中卻是類似於JSP標籤。這些瀏覽器特定的組件授權擴充在IE情形下稱作元素行為,而在最近版本的Firefox,Mozilla和Netscape 8情形下稱作可擴充的綁定。

四、 定製標籤

Internet Explorer,從版本5.5開始,支援定製的用戶端HTML元素的JavaScript授權。不象JSP標籤,這些對象並沒有在伺服器端被預先處理到HTML中。而是,它們成為一標準HTML物件模型的合法擴充,並且包括構造控制項在內的一切事情,都是動態地發生在用戶端的。同樣,基於Gecko-引擎的瀏覽器能夠用一個可重用功能動態地裝飾任何現有的HTML元素。

因此,我們有可能用具有HTML文法的方法、事件和屬性來構建一個具有豐富的UI組件的庫。這樣的組件可以被自由地混合於標準HTML中。內部地,這些組件將會與應用程式伺服器進行通訊-以AJAX風格。換句話說,你有可能(並且相對簡單地)構建自己的AJAX物件模型。

這種IE風味的方法被稱為HTC或HTML組件;其Gecko版本被稱為XBL-可擴充的綁定語言(eXtensible Bindings Language)。為了實現本文目的,我們集中於討論IE。

[1] [2]  下一頁



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.