虛擬面向?qū)ο?/h1>

2024-03-07 18:37 更新

由于JavaScript本身并不支持面向?qū)ο?,但是我們可以利用其Prototype去模擬部分面向?qū)ο蟮恼Z言特征。我們這兒要說的虛擬面向?qū)ο缶褪侵窪orado中提供的JavaScript模擬面向?qū)ο蟮木幊碳夹g(shù)。 在基礎(chǔ)教程中我們只介紹Dorado JS對象的使用和相關(guān)約定,而忽略對象的聲明、擴展等內(nèi)容。

虛擬屬性

我們使用Dorado提供的JSDOC的時候注意到,其中Dorado的JS對象通常都包含很多的attributes,如我們訪問URL:?http://dorado.bstek.com/jsdoc/ 訪問dorado.widget下的Button控件: 這些attributes就是Dorado對象的虛擬屬性,之所以稱它們?yōu)樘摂M屬性是,因為它們與Java中的屬性不同的地方在于,Java中的屬性我們都可以通過專用的getXXX/setXXX方法進行讀取操作,但是Dorado對象的虛擬屬性我們需要通過如下的方式:

var v = editor.get("value");
button.set("caption", "OK");

也就是說當(dāng)我們看到JSDOC中某一個Dorado控件具有的某些attributes,我們就可以通過get/set方法,例如剛才我們看到的Button中有icon屬性,則我們就可以通過如下的方式設(shè)置其icon屬性:

button.set("icon", "images/button_ok.gif");

下面介紹虛擬屬性的一些其他特色: set方法支持批量屬性設(shè)置 如下代碼,我們對一個對象的多個屬性進行賦值操作:

button.set("icon", "images/ok.gif");
button.set("caption", "OK");
button.onClick = function(){
    alert("You clicked OK.");
}

這種代碼有些羅嗦,尤其在屬性較多情況下更是如此,有什么簡化的辦法呢? 虛擬屬性的set方法支持屬性批量設(shè)置,如下:

button.set({
    icon: "images/ok.gif",
    caption: "OK",
    onClick: function() {
        alert("You clicked OK.");
    }
});

通過這種賦值方式可以大大的簡化代碼的書寫。 迭代式操作 通過前面的學(xué)習(xí)我們知道JSON可以構(gòu)造一個很復(fù)雜的樹結(jié)構(gòu)的對象,Dorado對象在很多情況下也是樹形結(jié)構(gòu),例如有一個oop為一個Dorado虛擬對象,其中含address虛擬屬性,而address本身又是一個Dorado虛擬屬性,我們希望取出其中的postCode,如果我們要存取postCode的值,可能的代碼有:

oop.get("address").get("postCode"); 
oop.get("address").set("postCode", "7232-00124");

但是利用虛擬屬性的功能,我們可以這么些代碼:

oop.get("address.postCode"); 
oop.set("address.postCode", "7232-00124");

這樣看起來代碼是不是簡潔多了,也很容易的就能讀懂代碼。對于迭代式get和set方法,還提供了一個更有意義的功能,即加入在迭代過程中遇到的不是一個Dorado的虛擬對象,而是一個標(biāo)準(zhǔn)的JSON對象,則這種迭代操作的處理機制依然有效。

事件

事件 Dorado為虛擬對象增加了很多事件,這些事件與通常Dom的事件并不一樣,是Dorado為虛擬對象專門增加的事件,事件的添加方法: 方法一

button1.addListener("onClick", function(self) {
     //此方法可以為一個事件添加多個監(jiān)聽函數(shù)
});

這是Dorado中內(nèi)部采用的添加事件的方法。

方法二

button1.set("onClick", function(self) {
     // 此方法只能定義一個監(jiān)聽函數(shù)
});

這兒要提一下虛擬屬性的功能,前面我們介紹過虛擬屬性,通過前面的學(xué)習(xí)上述代碼的意圖就是設(shè)置button1的onClick屬性,由于不存在實際的onClick屬性,且屬性的值我們給了一個function,則Dorado事件引擎會自動的調(diào)用button1.addListener處理機制,將這個function注冊到事件管理器中。推薦使用第二種方法,代碼更為直接,他們之間的差別在于虛擬屬性設(shè)置方法只能定義一個監(jiān)聽函數(shù),而addListener可以添加多個function。 下面說明事件的幾個公用特性,這些特性并不是每一個事件都有,但是這些特性是虛擬對象的事件的基本特性: self和arg Dorado中所有的事件都支持self和arg參數(shù),其中self表示激發(fā)事件的自身,如Button激活onClick事件,則self表示Button自身,如Editor激活onClick事件,則self表示Editor對象自身,arg的類型與具體事件類型有關(guān),很多情況下都是一個JSON對象,其中可能包含有非常豐富的傳入信息。不同的事件中arg的JSON對象的屬性是不一樣的,事件A可能arg中含有prop1,prop2,我們可以通過如下代碼獲取其屬性:

var v1 = arg.prop1;
var v2 = arg.prop2;

而事件B中可能傳入的信息就是prop3,prop4,則代碼就可能為:

var v3 = arg.prop3;
var v4 = arg.prop4;

不同事件的arg的差別,要通過JSDOC查看,例如我們看Button控件: http://dorado.bstek.com/jsdoc/ 其中的onClick事件: 注意其中arg的button,event和returnValue的說明 而其onRefreshDom事件的arg參數(shù)就為:

上面兩張截圖中onClick與onRefreshDom的事件中的arg參數(shù)是不一樣的。 this 如實做AJAX范例中,按鈕Ajax Multiply的onClick事件代碼中我們接觸到this的寫法,但是我們未細講這個this的含義:

var action = this.get("#multiplyAction");
dorado.MessageBox.prompt("Please input two numbers here", {
    defaultText: "3,5",
    callback: function(text) {
        var nums = text.split(",");
        var parameter = {
            num1: nums[0],
            num2: nums[1]
        };
        action.set("parameter", parameter).execute(function(result) {
            dorado.MessageBox.alert(nums[0] + " * " + nums[1] + " = " + result);
        });
    }
});

其實這個this指的就是按鈕所在的視圖View: 幾乎所有事件中的this均指向的是該控件隸屬的View對象,View對象的onCreate事件中的this是指向其自身的。 onCreate事件中的this是個例外,因為控件總是先被創(chuàng)建然后才被添加到控件樹上,因此在onCreate事件被觸發(fā)時控件并不知道其隸屬的View對象。所以onCreate事件中的this并不指向最終的View。而是指自身。

Dorado在所有的事件監(jiān)聽器中提供了一個view隱式變量指向當(dāng)前事件宿主所屬的View,此變量可以完全替代原先this的使用場景。它可以帶來以下幾個好處: 語義明確,很明顯 view.get("#dsPeople") 比 this.get("#dsPeople") 更加準(zhǔn)確的表達了代碼的含義。不用再擔(dān)心進入閉包和回調(diào)方法之后this的指向發(fā)生變化。即使是在控件的onCreate事件中也可以使用view隱式變量。而在之前的版本中,onCreate事件里this的指向是事件宿主自身,與其他事件并不相符。邏輯返回值 所有事件的返回值類型都是邏輯型,用于通知系統(tǒng)是否繼續(xù)觸發(fā)同一事件的后續(xù)監(jiān)聽器。不返回任何值則系統(tǒng)按true來處理。 一般情況下我們并不需要關(guān)注這個邏輯返回值,但有一種特殊情況: Dorado中對象某一個事件可以定義多個Listener的時候,這些Listener會按順序依次觸發(fā),如果我們希望在第一個事件觸發(fā)的過程中,屏蔽后面Listener的觸發(fā),則我們需要在第一個Listener中明確的返回一個false。這樣后面的事件就會被跳過,不再執(zhí)行。 processDefault 很多beforeXXX事件的arg參數(shù)中都支持一個名為processDefault的可寫屬性,用于通知系統(tǒng)是否要執(zhí)行該事件所代表的后續(xù)操作。 如下的一個范例,我們對一個DataType添加一個beforeRemove的事件,并在其中判斷,如果是已婚的則不允許刪除,通過MessageBox給出提示信息,并設(shè)置arg的processDefault為false,用以告訴beforeRemove動作如果是已婚則不執(zhí)行默認的刪除動作。

employeeDataType.addListener("beforeRemove", function(self, arg) {
    if (arg.entity.get("married")) {
        dorado.MessageBox.alert("已婚的員工不能被刪除!");
        arg.processDefault = false;
    }
});

拋出一個異常,同樣可以達到類似的目的。

employeeDataType.addListener("beforeRemove", function(self, arg) {
    if (arg.entity.get("married")) {
        throw new dorado.Exception("已婚的員工不能被刪除!");
    }
});

兩種方法其實有區(qū)別,可能導(dǎo)致不同的結(jié)果!例如我們對10條員工記錄,循環(huán)做刪除動作,例如第三條為已婚員工,則如果是用processDefault = false的處理機制,最終系統(tǒng)的效果是刪除第三條的時候給出用戶警告,但是系統(tǒng)會接著刪除第四,五條直到第十條記錄,也就是說會繼續(xù)循環(huán),最終結(jié)果是除了第三條記錄之外,其它記錄全部被刪除。但是如果采用throw new dorado.Exception()處理機制,則循環(huán)到第三條彈出異常,并終止循環(huán),后面的記錄不會不刪除。它們之間的差別,用Java關(guān)鍵字表示,就是processDefault相當(dāng)與循環(huán)體中的continue,而throw new Dorado.Exception()相當(dāng)與break。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號