5.2 函數的聲明與調用
在WML Script中,函數是一種能夠完成某種功能的代碼塊,并可以在腳本中被事件處理或被其他語句調用,也可以被WML程序所處理和調用。一般地,當我們編寫WML Script腳本時,如果腳本中的代碼長度還是很長,則一般還可以根據功能將函數再進行劃分,分成為幾個功能更加單一的函數。雖然說這樣對長代碼的處理方法并不是編寫腳本程序的強制性要求,但通過函數的劃分和運用,我們可以使得WML Script腳本具有更好的可讀性,也便于我們對腳本程序的編寫與調試。而且,如果在某些腳本中有多處完全相同的代碼塊,那么我們也可以將這些代碼快些為一個函數,然后在腳本中調用這個函數,從而提高代碼的重要性,簡化代碼的編寫工作。
WML Script的函數共用和Jave語言、C/C++語言的函數有所不同。我們知道,Jave語言、C/C++語言中有函數和過程之分,函數能夠完成一定的功能并有返回值,而過程進可完成一定的功能但沒有返回值。可是,WML Script中并不區分函數和過程,因為它只有函數,沒有過程。WML Script的函數完成一定功能后始終有返回值,不過返回值分兩種情況,即非空的返回值和空字符串("")形式的返回值。前者是真正的返回值,后者其實相當于沒有返回值。也就是說,WML Script中的函數同時具有其他語言中的函數和過程的功能。
5.2.1 函數的聲明
使用函數時,要根據函數的調用使用,而調用函數前必須聲明函數,也就是需要先定義函數。WML Script中定義函數的一般方式如下:
function函數名(參數列表)
{
代碼塊
};
另外,WML Script規定使用extern關鍵字來聲明一個外部函數:
extern function函數名(參數列表)
{
代碼塊
};
從中可以看出,函數的定義有以下3部分組成:
(1)函數名。即函數的名稱,其命名規則應遵守WML Script的標識規則。調用函數時都是通過函數名進行調用的,所以函數必須要有函數名。
函數命名時,一般要使用能夠描述函數功能的但此來作為函數名,也可以使用多個單詞組合進行命名,這樣做的好處是能夠提高WML Script腳本的可讀性。
函數名在同一個WML Script腳本文件里必須是唯一的。如若不然,則會導致函數定義混亂。
(2)參數列表。即調用函數時需要的參數。參數列表通常是可選的,有的函數需要,有的函數可能不需要。參數列表的作用是向函數傳遞一些參數,使得函數可以直接使用這些參數的值。
調用函數的時候,參數個數和類型必須和函數定義示所聲明的參數個數即類型保持一致。而且函數的參數就如同似函數體內的局部變量,它們在函數調用的時候被初始化。
(3)代碼塊。它是函數的主體部分。代碼塊中的代碼包含在以對花括號({ })中,代碼塊可以執行并完成函數的功能。編寫代碼塊是應當遵循WML Script的編程規則。
有時,函數需要返回一個值給調用函數的語句,則應該在代碼塊的后面一行使用return語句,返回所需的數值。
與C/C++等語言類似,WML Script的函數是可以嵌套的,以就是說,在一個函數中還可以調用其他函數。但是,函數聲明是不能嵌套,這是WML Script的強制性規定。
下面幾行語句就是定義函數的簡單例子:
function currencyConverter(currency,exchangeRate)
{
return currency*exchangeRate;
};
其中,該函數的名稱為currencyConverter,參數有currency和exchangeRate兩個,函數代碼塊包含一條語句,用于返回currency和exchangeRate的乘積。
下面是一個使用extern定義外部函數的例子。其中函數名為textIt,它沒有參數,函數體中定義了兩個賦值變量,一個賦整數,一個賦函數值:
extern function testIt(){
var USD=10;
var FIM =currencyConverter(USD,5.3)
};
5.2.2 函數的調用
編寫好的函數必須經過合法的調用,才可以發揮它應用的作用。函數調用將返回一個值,比如一個計算結果。WML Script中的函數主要可以分為內部函數、外部函數和庫函數,下面我們就介紹這3類函數的調用方法。
內部函數
所謂內部函數是指函數的定義與其調用函數在同一個腳本文件內的函數,對內部函數的調用稱為內部調用。內部函數的調用非常簡單,只需提供函數名和所需參數值即可,參數值必須和函數定義時指定的參數個數即類型一致。而且函數調用需要使用操作符來接收或處理被調用的返回值。
內部函數可以在其定義之前調用,也可以在其定義之后調用。例如,下面就是一個在函數定義之后調用的例子。
function test1(val){
return val*val;
};
function test2(param){
return test1(param+1);
}; |
這個例子中定義了兩個函數test1和test2。test1函數用于計算給定參數值的平方并將結果返回;test2函數將給定的參數值加1,然后這個和為參數值,來調用test1函數,得到結果后在將給結果返回到調用test2函數的語句。
注意,本例中test2函數調用了test1函數,這種在函數中調用其他函數的方法稱為函數調用嵌套。WML Script的內部函數、外部函數和庫函數都支持嵌套調用,后面我們專門介紹這方面的內容。
外部函數
外部函數使一個在WML Scrupt外部文件中定義的函數。調用外部函數的方法與調用內部函數的方法基本類似,不同之處在于調用處外部函數時一是要指定外部文件的地址即名稱,二是要在調用的外部函數名的前面加上外部文件的名稱。
WML Script規則使用use url來指定外部文件,語法格式為:
use url還有外部函數的外部文件名 外部文件所在的URL;
這樣,WML Script的預編譯頭就可以將外部文件映射為一個可以在內部使用的標識。然后,使用這個標識并加上井號鍵(#)和標準的函數調用即可實現外部函數調用,語法格式為:
外部文件名#外部函數(參數列表);
例如,http://www.host.com/script下有我們需要的外部文件,名為OtherScript,所以我們可使用use url來指定該文件:
use url OtherScript"http://www.host.com/script"
這一外部文件中含有我們需要調用的外部函數testme,則可采用“外部文件名#外部函數(參數列表)”的形式來調用它:
OtherScript#testme(param+1);
這個例子完整的寫出來,就是下面的程序:
use url OtherScript"http://www.host.com/script"
function test(param){
return OtherScript#testme(param+1);
};
庫函數
特別指定,WML Script的庫函數一律是指它的標準庫函數。因為與標準庫函數對應,WML Script還有一些非標準的庫函數。我們這里先介紹標準庫函數,非標準庫函數后面再介紹。
所有庫函數都有所數的庫,函數的庫中通常含有一類函數。因此,調用某個庫函數時,一要指定它的庫名,二要指定它的函數名。WML Script規定,調用標準庫函數時可以通過在函數庫的名字后面加上句點號(.)和庫函數的標準調用來實現,語法格式為:
函數庫名.函數名(參數列表);
例如,WML Script的浮點庫即Float庫中有一個開根方的函數sqrt,該函數只有一個參數,那么調用squrt庫函數的方法為:
Float.sqrt(number);//這里要求number大于或等于0
下面給出了調用庫函數的簡單例子。首先一param參數值調用Lang.abs()函數,返回結果加1后再作為參數調用Float.sqrt()函數,它的返回結果作為內部函數test的返回值:
function test(param){
return Float.sqrt(Lang.abs(param)+1);
};
2.3 函數的嵌套調用
WML Script的函數定義都是互相平行、獨立的,定義函數的時候我們不能在一個函數內定義另外一個函數,也就是說,函數定義是不能嵌套的。但是,函數調用確是可以嵌套的,也就是說,我們可以在調用一個函數的過程中調用另外一個函數。
它的執行過程是:
(1)執行a函數開頭部分;
(2)遇到調用b函數的操作語句,流程則專區執行b函數;
(3)執行b函數開頭部分;
(4)遇到調用c函數的操作語句,流程則專區執行c函數;
(5)執行b函數,如果沒有其他嵌套的函數,則完成c函數的全部操作;
(6)返回調用c函數的語句,即返回到b函數;
(7)繼續執行b函數中尚未執行的操作,直到b函數結束;
(8)返回a函數中調用b函數的語句;
(9)繼續執行a函數的剩余操作,直到函數結束。
function myFunC(param1){
return param1*param1=Float.squt(Lang.abs(param)+1);
};
function myFunB(param0){
return myFunC(param0+1)*|param0+12;
};
function myFunA(param){
return myFunB(param*param+1);
};
5.3 預編譯WML Script的預編譯主要用于在編譯階段控制編譯器的行為。與編譯頭一般在文件開頭和函數聲明之前指定,WML Script規定所有的預編譯頭都是一關鍵詞use加上指定的預編譯屬性進行指定。
在大多數的編程中,我們比較長用的預編譯行為主要涉及外部文件聲明、訪問權和Meta信息設置。
5.3.1 外部文件
我們知道,使用URL地址可以定位一個WML Script文件。利用該URL地址;在WML Script編程中我們可以通過預編譯來調用WML Script的外部文件,外部文件預編譯頭的聲明方法是use url,其語法格式如下:
use url外部文件名 "URL"地址
這樣,我們在當前文件的編程中就可以使用該預編譯頭聲明的外部文件,從而可以調用該外部文件的函數。其語法格式為:
外部文件名#函數名(參數列表);
例如,我們希望在當前的WML Script程序中調用OtherScript外部文件中的check()函數,而且我們知道OtherScript文件的URL地址為http://www.host.com/app/script。因此,我們可以使用use url來聲明這一外部文件:
use url OtherScript"http://www.host.com/script"
隨后,我們就可以在程序中調用OtherScript中的check()函數了:
function test(par1,par2)
{
return OtherScript#check(par1,parr2);
};
其中調用執行的過程如下:
(1)找到WML Script外部文件的URL地址;
(2)當前函數從指定的URL地址值裝載外部文件;
(3)檢測外部文件的內容,并執行其中的check()函數。
ure url 預編譯頭指定的外部文件名在當前程序中必須唯一,用戶不能指定不同URL地址的同名外部文件,否則在調用外部文件時就會發生混亂。
另外,use url預編譯頭中的URL地址也可以是相對URL地址。相對URL的起始位置是當前程序文件所在的位置,并在此基礎上根據URL進行定位。
如果URL地址中的字符包含有轉義字符,則WML Script將根據轉義要求進行轉義。不過,程序在編譯的時候編譯器并不會對他們進行轉義,而是在程序執行時完成,檢查URL格式和URL地址的有效性。
5.3.2 訪問權限
我們可以使用訪問權限預編譯設保護文件的內容,實現訪問控制。WML Script編程中,必須在調用外部函數之前使用訪問權限預編譯頭聲明外部文件的訪問權限。不過,WML Script訪問權限檢查的缺省值是不進行檢查,即disabled.但訪問權限一經聲明,以后當調用外部函數的時候,編譯器就會檢查外部文件的訪問權限,以決定調用這是否有權使用該文件及其內含函數。
訪問權限預編譯頭的聲明方法是use access,其語法格式如下:
use access domain操作域名 path操作路徑:
訪問權限預編譯頭通過指定domain和path屬性來決定編譯器將要進行什么樣的檢查工作。如果文件有domain或者path屬性,那么文件所在的URL就必須和屬性中的值一致。比較時,域和路徑都依據URL大寫規則進行比較。具體的比較預則如下:
(1)操作域與URL中的域后綴相匹配。與后綴匹配是值所有的子域從后向前都必須一致。例如:www.wapforum.org和wapforum.org相匹配,而與forum.org并不匹配。
(2)操作路徑和URL中的路徑前綴相匹配。路徑前綴匹配是值從前向后必須一致。例如:“/X/Y”與“/X”相匹配,而不是和“/XZ”相匹配。
(3)卻省的domain數行為當前的文件域,就是“/”。
不過,為了簡化編程,有時WMLScript并不需要直到外部文件的絕對路徑,我們只需提供文件的相對URL即可,用戶瀏覽器執行程序是卡相對路徑自動轉換為絕對路徑,根據路徑屬性進行匹配。例如:如果訪問權限預編譯頭及其指定屬性為:
use access domain"wapforum.org"path"/finance";
則可以使用以下的路徑來調用指定文件中的外部函數,它們都符合相對URL地址匹配規則:
http://wapforum.org/finance/money.cgi
http://www. wapforum.org/finance/money.cgi
http://www. wapforum.org/finance/demos/packages.cgi?x+123&y+456
而以下的路徑調用則非法的,因為它們或者操作域不對,或者URL地址不能與指定的相對URL相匹配:
heep//www.test.net/finance
http//www.qapforum.org/internal/foo.wml
需要強調指出的是,WML Script規定,同一程序中只能定義一個訪問權限與編譯頭,否則就會導致編譯錯誤。
5.3.3 Meta 信息
我們還可以通過與編譯頭的形式聲明WML Script文件的Meta信息。Meta信息主要用于指定文件所需Mete屬性的屬性名(Property name)、屬性值(Content)以及文件的配置(信息),屬性都屬于字符串類型的數據。Mate信息域編譯頭使用use meta聲明,其語法格式為:
usr meta 屬性 該屬性Meta信息:
Meta的屬性主要包括Name、HTTP Equiv和User Agent三種,下面我們分別講解它們的聲明方法:
(1)Name。該屬性用于指定服務器使用的Meta信息。這些信息僅供服務使用,用戶瀏覽器并不理會這些信息。
例如,以下Name屬性的Meta信息指定了服務器的創建時間:
use meta name "Created""26-June-2000";
該信息只會作用于服務器,而不會影響用戶瀏覽器的操作。
(2)HTTP Equiv。該屬性用于指定需要解釋為HTTP頭的Meta信息。對于已經編譯的文件來說,當它到達用戶瀏覽器前,WML Script將根據HTTP Equiv屬性指定的Meta信息將文件轉換為WSP或HTTP的響應頭,進行文件的解釋和執行。
例如,以下聲明的http equiv屬性指定按照腳本語言的關鍵字來解釋當前文件:
use meta http equiv"Keywords""Script,Language";
(3)User Agent。該屬性用于定義用戶瀏覽器使用的數據類型。例如:
use meta user agent"Type""Test";
它指定當前數據必須立即發送給用戶瀏覽器,然后馬上清除掉。
5.4 執行時的錯誤檢測與處理WML Script函數的功能提供用戶服務,并希望用戶界面能在任何的狀況下運作順利,因此錯誤的處理是最大的課題,這表示了語言可能不提供預期的機制,如他應該可以防止錯誤發生或提醒用戶注意并采取適當的動作,種植儲蓄執行是最后的手段。下面幾個小節列出了當為碼下載并執行時會發生的錯誤,一些程序上的錯誤并不在談論的范圍(如無窮循環),像這類的例子就需要手動來終止。
5.4.1 錯誤檢測
錯誤檢測工具能讓你檢測錯誤但會干擾系統的動作,因為WML Script是弱格式語言,所以由一些特殊功能的工具來檢測有invalid數據格式所引起的錯誤:
檢測給定的變量包含的是正確值:WML Scritp含有格式確認函數庫程序如:Lang.isInt()Lang.isFloat()、Lang.parseInt()、Lang.parseFloat。
檢測給定的變量包含的只是正確的格式:WMLScript含有運算符typeof與isvalid能讓你使用。
5.4.2錯誤處理
錯誤處理是在發生錯誤之后,有些狀況是錯誤檢測無法防止的,如內存限制后外部信號等,或者是數據很難處理,如溢出(overflow)或虧失(underflow),而這些狀況可以分為兩類:
嚴重錯誤(fatalerror):這種錯誤會造成程序終止,因為WML Scritp程序會讓一些用戶界面調用,程序終止通常會跟調用它的用戶界面發出信號,用戶界面就會告知用戶這個錯誤。
錯誤(non-fatalerrow):這種錯誤會把信號傳回程序,如一些特殊的值,然后由程序決定所要采取的行動。
下列的錯誤是根據他們的嚴重性來區分。
5.4.3 嚴重錯誤(fatalerror)
下面的小節會討論WML Script的嚴重錯誤。
位碼錯誤(bytedode error)
這些錯誤跟位碼與由WML Script位碼解譯器所執行的指令有關他們指出了錯誤的元素群、無效的指令、指令所使用的參數無效,或指令無法執行。
驗證錯誤(verification failed)
說明:調用的程序中的特定位碼無法通過驗證。
如何發生:每次程序試著用外部程序。
范例:var a = 3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:當檢測位碼驗證式。
解決方法:終止程序與WML Script解譯其調用者的錯誤信號。
說明:調用一個函數庫程序時發生嚴重錯誤。
如何發生:每次調用函數庫程序。
范例:var a = string.format(param)
嚴重性:嚴重。
判定狀況:無
解決方法:終止程序與WML Script解譯其調用者的錯誤信號。
說明:調用函數參數的數目跟被調用函數的參數數目不符合。
如何發生:調用外部程序。
范例:編譯器參生一個無效的參數給予指令使用,或者被調用的程序參數數目改變了。
嚴重性:嚴重。
判定狀況:無
嚴重性:嚴重。
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明: 在特定的程序中找不到所需要的外部程序。
如何發生:調用外部程序。
范例: var a =3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明: 由于在網絡服務器的程序存取又無法修復的錯誤或特定程序并不在網絡服務器中所引起的程序無法載入。
如何發生:調用外部程序。
范例: var a =3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明: 存取錯誤,所調用的外部程序加了保護。
如何發生:調用外部程序
范例:var a =3*OtherScript#doThis(param)
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明: 因為程序錯誤造成stack underflow。
如何發生:程序要取出(pop)一個空堆
范例: 當組譯器產生錯誤碼。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明:執行調用Lang.abort() 是發生的錯誤。
如何發生:每當程序調用Lang.abort()函數。
范例: Lang.abort("unrecoverable error")
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明:發生堆棧溢出。
如何發生:程序資源太多或要推入太多的變量到運算之中。
范例: function f|(x)(f(x+1););
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明:沒有多余的內存可供解譯器使用。
如何發生:作業系統無法配置多余的空間給解譯器適使用。
范例: function f(x){
x=x+"abcdefghijklmnopqrstuvxyz";
f(x) ;
};
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明:用戶終止程序的執行(如按下reset鈕)
如何發生:隨時。
范例: 當應用程序正在執行是用戶按下reset鈕。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
說明:當程序執行中,發生了外部嚴重的錯誤。
如何發生:隨時。
范例: 電力微弱,系統自動。
嚴重性:嚴重。
判定狀況:無
解決方案:終止程序與WML Script解譯器調用著的錯誤信號。
5.4.4 一般錯誤(Nonfatal error)
下面說明了WML Script的一般錯誤:
計算錯誤(computational error)
這些錯誤是由于WML Script數學上的運算所造成。
除以零(divide by zero)
說明:發生了除以零的狀況
如何發生:當程序中有除以零的狀況。
范例:var a= 10;
var b= 0;
var x= a/b;
var y= a div b;
var z= a%b;
a/=b;
嚴重性: 一般。
判定狀況:高
解決方案:產生結果為invalid。
說明:發生了除以零的狀況
如何發生:程序要執行浮點數運算。
范例:var a = Float.precision();
var b = Float.precision();
var c = a* b
嚴重性:一般。
判定狀況:高,在某些狀況很困難。
解決方法:產生的結果為浮點數值0.0
常數參考錯誤(constant reference error)
說明:所參考的浮點數實字為not a number。
如何發生:程序試著存取一個浮點數實字但組譯器產生了not a number的浮點數常數。
范例:參考浮點數常數。
嚴重性:一般。
判定狀況:高
解決方法:這會產生invalid值。
說明:參考的浮點數實字不是正無窮大就是負無窮大的浮點數常數。
如何發生:程序試著存取一個浮點數實字但組譯器產生了正無窮大或負無窮大的浮點數常數。
范例:參考浮點數常數。
嚴重性:一般。
判定狀況:高
解決方法:這會產生invalid值。
說明:需要參照浮點數值所發生的錯誤。
如何發生:程序需要使用浮點數值但環境值支持整數值。
范例:var a = 3.14;
嚴重性:一般
判定狀況:高
解決方法:這會產生invalid值。
轉換錯誤
這個錯誤的發生同WML Script所支持的自動轉換有關。
說明:欲轉換成整數值,但這個值超過整數所能接受的范圍(正或負)。
如何發生:程序試著自動轉換成整數時。
范例: var a = -"99999999999999999999999999999999999999999";
嚴重性:一般
判定狀況:高
解決方法:這會產生invalid值。
說明:欲轉換成浮點數,但這個值小于浮點數所能接受的范圍(正或負)。
如何發生:程序時值自動轉換成浮點數時。
范例:var a = -"99999999999999999999999999999999999999999";
嚴重性:一般
判定狀況:高
解決方法:這會產生invalid值。
說明:欲轉換成浮點數,但這個值小于浮點數所能接受的范圍(正或負)。
如何發生:程序時值自動轉換成浮點數時。
范例:var a = -"99999999999999999999999999999999999999999";
嚴重性:一般
判定狀況:高
解決方法:這會產生浮點數0.0。
|----------------------------------------------------------------------------------------|
|----------------------------------------------------------------------------------------|