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。
|----------------------------------------------------------------------------------------|
|----------------------------------------------------------------------------------------|