高级 JScript.docx
《高级 JScript.docx》由会员分享,可在线阅读,更多相关《高级 JScript.docx(14页珍藏版)》请在冰点文库上搜索。
高级JScript
创建高级对象
使用构造函数来创建对象
构造函数是一个函数,调用它来例示并初始化特殊类型的对象。
可以使用new关键字来调用一个构造函数。
下面给出了使用构造函数的新示例。
varmyObject=newObject();//创建没有属性的通用对象。
varmyBirthday=newDate(1961,5,10);//创建一个Date对象。
varmyCar=newCar();//创建一个用户定义的对象,并初始化其属性。
通过构造函数将一个参数作为特定的this关键字的值传递给新创建的空对象。
然后构造函数负责为新对象执行适应的初始化(创建属性并给出其初始值)。
完成后,构造函数返回它所构造的对象的一个参数。
编写构造函数
可以使用new运算符结合像Object()、Date()和Function()这样的预定义的构造函数来创建对象并对其初始化。
面向对象的编程其强有力的特征是定义自定义构造函数以创建脚本中使用的自定义对象的能力。
创建了自定义的构造函数,这样就可以创建具有已定义属性的对象。
下面是自定义函数的示例(注意this关键字的使用)。
functionCircle(xPoint,yPoint,radius){
this.x=xPoint;//圆心的x坐标。
this.y=yPoint;//圆心的y坐标。
this.r=radius;//圆的半径。
}
调用Circle构造函数时,给出圆心点的值和圆的半径(所有这些元素是完全定义一个独特的圆对象所必需的)。
结束时Circle对象包含三个属性。
下面是如何例示Circle对象。
varaCircle=newCircle(5,11,99);
使用原型来创建对象
在编写构造函数时,可以使用原型对象(它本身是所有构造函数的一个属性)的属性来创建继承属性和共享方法。
原型属性和方法将按引用复制给类中的每个对象,因此它们都具有相同的值。
可以在一个对象中更改原型属性的值,新的值将覆盖默认值,但仅在该实例中有效。
属于这个类的其他对象不受此更改的影响。
下面给出了使用自定义构造函数的示例,Circle(注意this关键字的使用)。
Circle.prototype.pi=Math.PI;
functionACirclesArea(){
returnthis.pi*this.r*this.r;//计算圆面积的公式为?
r2。
}
Circle.prototype.area=ACirclesArea;//计算圆面积的函数现在是CirclePrototype对象的一个方法。
vara=ACircle.area();//此为如何在Circle对象上调用面积函数。
使用这个原则,可以给预定义的构造函数(都具有原型对象)定义附加属性。
例如,如果想要能够删除字符串的前后空格(与VBScript的Trim函数类似),就可以给String原型对象创建自己的方法。
//增加一个名为trim的函数作为
//String构造函数的原型对象的一个方法。
String.prototype.trim=function()
{
//用正则表达式将前后空格
//用空字符串替代。
returnthis.replace(/(^\s*)|(\s*$)/g,"");
}
//有空格的字符串
vars="leadingandtrailingspaces";
//显示"leadingandtrailingspaces(35)"
window.alert(s+"("+s.length+")");
//删除前后空格
s=s.trim();
//显示"leadingandtrailingspaces(27)"
window.alert(s+"("+s.length+")");
递归
递归是一种重要的编程技术。
该方法用于让一个函数从其内部调用其自身。
一个示例就是计算阶乘。
0的阶乘被特别地定义为1。
更大数的阶乘是通过计算1*2*...来求得的,每次增加1,直至达到要计算其阶乘的那个数。
下面的段落是用文字定义的计算阶乘的一个函数。
“如果这个数小于零,则拒绝接收。
如果不是一个整数,则将其向下舍入为相邻的整数。
如果这个数为0,则其阶乘为1。
如果这个数大于0,则将其与相邻较小的数的阶乘相乘。
”
要计算任何大于0的数的阶乘,至少需要计算一个其他数的阶乘。
用来实现这个功能的函数就是已经位于其中的函数;该函数在执行当前的这个数之前,必须调用它本身来计算相邻的较小数的阶乘。
这就是一个递归示例。
递归和迭代(循环)是密切相关的—能用递归处理的算法也都可以采用迭代,反之亦然。
确定的算法通常可以用几种方法实现,您只需选择最自然贴切的方法,或者您觉得用起来最轻松的一种即可。
显然,这样有可能会出现问题。
可以很容易地创建一个递归函数,但该函数不能得到一个确定的结果,并且不能达到一个终点。
这样的递归将导致计算机执行一个“无限”循环。
下面就是一个示例:
在计算阶乘的文字描述中遗漏了第一条规则(对负数的处理),并试图计算任何负数的阶乘。
这将导致失败,因为按顺序计算-24的阶乘时,首先不得不计算-25的阶乘;然而这样又不得不计算-26的阶乘;如此继续。
很明显,这样永远也不会到达一个终止点。
因此在设计递归函数时应特别仔细。
如果怀疑其中存在着无限递归的可能,则可以让该函数记录它调用自身的次数。
如果该函数调用自身的次数太多,即使您已决定了它应调用多少次,就自动退出。
下面仍然是阶乘函数,这次是用JScript代码编写的。
//计算阶乘的函数。
如果传递了
//无效的数值(例如小于零),
//将返回-1,表明发生了错误。
若数值有效,
//把数值转换为最相近的整数,并
//返回阶乘。
functionfactorial(aNumber){
aNumber=Math.floor(aNumber);//如果这个数不是一个整数,则向下舍入。
if(aNumber<0){//如果这个数小于0,拒绝接收。
return-1;
}
if(aNumber==0){//如果为0,则其阶乘为1。
return1;
}
elsereturn(aNumber*factorial(aNumber-1));//否则,递归直至完成。
}
变量范围
JScript有两种变量范围:
全局和局部。
如果在任何函数定义之外声明了一个变量,则该变量为全局变量,且该变量的值在整个持续范围内都可以访问和修改。
如果在函数定义内声明了一个变量,则该变量为局部变量。
每次执行该函数时都会创建和破坏该变量;且它不能被该函数外的任何事物访问。
像C++这样的语言也有“块范围”。
在这里,任何一对“{}”都定义新的范围。
JScript不支持块范围。
一个局部变量的名称可以与某个全局变量的名称相同,但这是完全不同和独立的两个变量。
因此,更改一个变量的值不会影响另一个变量的值。
在声明局部变量的函数内,只有该局部变量有意义。
varaCentaur="ahorsewithrider,";//aCentaur的全局定义。
//JScript代码,为简洁起见有省略。
functionantiquities()//在这个函数中声明了一个局部aCentaur变量。
{
//JScript代码,为简洁起见有省略。
varaCentaur="AcentaurisprobablyamountedScythianwarrior";
//JScript代码,为简洁起见有省略。
aCentaur+=",misreported;thatis,";//添加到局部变量。
//JScript代码,为简洁起见有省略。
}//函数结束。
varnothinginparticular=antiquities();
aCentaur+="asseenfromadistancebyanaiveinnocent.";
/*
在函数内,该变量的值为"AcentaurisprobablyamountedScythianwarrior,
misreported;thatis,";在函数外,该变量的值为这句话的其余部分:
"ahorsewithrider,asseenfromadistancebyanaiveinnocent."
*/
很重要的一点是注意变量是否是在其所属范围的开始处声明的。
有时这会导致意想不到的情况。
tweak();
varaNumber=100;
functiontweak(){
varnewThing=0;//显式声明newThing变量。
//本语句将未定义的变量赋给newThing,因为已有名为aNumber的局部变量。
newThing=aNumber;
//下一条语句将值42赋给局部的aNumber。
aNumber=42;
if(false){
varaNumber;//该语句永远不会执行。
aNumber=123;//该语句永远不会执行。
}//条件语句结束。
}//该函数定义结束。
当JScript运行函数时,首先查找所有的变量声明,
varsomeVariable;
并以未定义的初始值创建变量。
如果变量被声明时有值,
varsomeVariable="something";
那么该变量仍以未定义的值初始化,并且只有在运行了声明行时才被声明值取代,假如曾经被声明过。
JScript在运行代码前处理变量声明,所以声明是位于一个条件块中还是其他某些结构中无关紧要。
JScript找到所有的变量后立即运行函数中的代码。
如果变量是在函数中显式声明的—也就是说,如果它出现于赋值表达式的左边但没有用var声明—那么将把它创建为全局变量。
复制、传递和比较数据
在JScript中,对数据的处理取决于该数据的类型。
按值和按引用的比较
Numbers和Boolean类型的值(true和false)是按值来复制、传递和比较的。
当按值复制或传递时,将在计算机内存中分配一块空间并将原值复制到其中。
然后,即使更改原来的值,也不会影响所复制的值(反过来也一样),因为这两个值是独立的实体。
对象、数组以及函数是按引用来复制、传递和比较的。
当按地址复制或传递时,实际是创建一个指向原始项的指针,然后就像拷贝一样来使用该指针。
如果随后更改原始项,则将同时更改原始项和复制项(反过来也一样)。
实际上只有一个实体;“复本”并不是一个真正的复本,而只是该数据的又一个引用。
当按引用比较时,要想比较成功,两个变量必须参照完全相同的实体。
例如,两个不同的Array对象即使包含相同的元素也将比较为不相等。
要想比较成功,其中一个变量必须为另一个的参考。
要想检查两个数组是否包含了相同的元素,比较toString()方法的结果。
最后,字符串是按引用复制和传递的,但是是按值来比较的。
请注意,假如有两个String对象(用newString("something")创建的),按引用比较它们,但是,如果其中一个或者两者都是字符串值的话,按值比较它们。
注意 鉴于ASCII和ANSI字符集的构造方法,按序列顺序大写字母位于小写字母的前面。
例如"Zoo"小于"aardvark"。
如果想执行不区分大小写的匹配,可以对两个字符串调用toUpperCase()或toLowerCase()。
传递参数给函数
按值传递一个参数给函数就是制作该参数的一个独立复本,即一个只存在于该函数内的复本。
即使按引用传递对象和数组时,如果直接在函数中用新值覆盖原先的值,在函数外并不反映新值。
只有在对象的属性或者数组的元素改变时,在函数外才可以看出。
例如(使用IE对象模式):
//本代码段破坏(覆盖)其参数,所以
//调用代码中反映不出变化。
functionClobber(param)
{
//破坏参数;在调用代码中
//看不到。
param=newObject();
param.message="Thiswillnotwork";
}
//本段代码改变参数的属性,
//在调用代码中可看到属性改变。
functionUpdate(param)
{
//改变对象的属性;
//可从调用代码中看到改变。
param.message="Iwaschanged";
}
//创建一个对象,并赋给一个属性。
varobj=newObject();
obj.message="Thisistheoriginal";
//调用Clobber,并输出obj.message。
注意,它没有发生变化。
Clobber(obj);
window.alert(obj.message);//仍然显示"Thisistheoriginal"。
//调用Update,并输出obj.message。
注意,它已经被改变了。
Update(obj);
window.alert(obj.message);//显示"Iwaschanged"。
检验数据
当按值进行检验时,是比较两个截然不同的项以查看它们是否相等。
通常,该比较是逐字节进行的。
当按引用进行检验时,是看这两项是否是指向同一个原始项的指针。
如果是,则比较结果是相等;如果不是,即使它们每个字节都包含完全一样的值,比较结果也为不相等。
按引用复制和传递字符串能节约内存;但是由于在字符串被创建后不能进行更改,因此可以按值进行比较。
这样可以检查两个字符串是否包含相同的内容,即使它们是完全独立产生的。
使用数组
数组下标
JScript中的数组是稀疏的。
也就是说,如果一个数组具有三个元素,编号分别为0、1和2,您就可以创建元素50,而不必担心从3到49的参数。
如果该数组有一个自动的length变量,(请参阅内部对象了解有关数组长度的自动监控的说明),该length变量被设为51,而不是4。
当然您可以创建各元素的编号之间没有间隙的数组,不过没有必要这样做。
在JScript中,对象和数组几乎相同。
两个主要差别是对象没有自动长度属性,而数组没有对象的属性和方法。
数组寻址
使用方括号“[]”来寻址数组。
方括号中是一个数值或一个值为整数的表达式。
下面的示例假定在脚本的其他地方已定义了entryNum变量,且已赋值。
theListing=addressBook[entryNum];
theFirstLine=theListing[1];
将对象作为关联数组
通常,使用点运算符“.”访问对象的属性。
例如,
myObject.aProperty
在这里,属性名称是一个标识符。
也可以用索引运算符“[]”访问对象的属性。
在这里,是把对象看作一个关联数组。
关联数组是一种数据结构,它可以动态地将任意的数据的值与任意的字符串相关联。
例如,
myObject["aProperty"]//与上面相同。
尽管索引运算符更多地用于访问数组元素,当用于对象时,索引总是以字符串文字表示的属性名称。
注意访问对象属性的两种方法的重要差异。
运算符
属性名称作为
对属性名称的处理
点“.”
标识符
不能作为数据处理
索引“[]”
字符串文字
能被作为数据处理
在运行之前并不知道属性名称时,这个差异会有用(比如基于用户输入构造对象时)。
要想从一个关联数组提取所有的属性,必须用for…in循环。
JScript
语言参考
特殊字符
JScript提供了一些特殊字符,允许在字符串中包括一些无法直接键入的字符。
每个字符都以反斜杠开始。
反斜杠是一个转义字符,表示JScript解释器下面的字符为特殊字符。
转义序列
字符
\b
退格
\f
走纸换页
\n
换行
\r
回车
\t
横向跳格(Ctrl-I)
\'
单引号
\"
双引号
\\
反斜杠
请注意,由于反斜杠本身用作转义符,因此不能直接在脚本中键入一个反斜杠。
如果要产生一个反斜杠,必须一起键入两个反斜杠(\\)。
document.write('TheimagepathisC:
\\webstuff\\mypage\\gifs\\garden.gif.');
document.write('Thecaptionreads,"Afterthesnowof\'97.Grandma\'shouseiscovered."');
脚本问题解答
如果不够细致,任何编程语言都有一些可能发生错误的地方,而且每种语言都有其特殊之处。
例如,对于null值:
JScript中这个值与C或C++语言中的Null值所起的作用是不一样的。
下面提供了一些在编写JScript脚本时可能遇到的问题。
语法错误
由于编程语言中的语法比自然语言的语法要严格得多,因此在编写脚本时对细节应倍加关注。
例如,如果您本意是将字符串作为某个参数,但是在键入时忘了使用引号引起来,就会产生问题。
脚本解释顺序
对JScript的解释是Web浏览器的HTML语法分析处理的一部分。
因此,如果在文档的
标识中放置了一个脚本,则将在检查所有的标识之前加以解释。
如果在
标识中将创建对象,但由于在分析处理标识时这些对象尚不存在,因而不能被脚本操作。
注意 本情况特定于IE。
ASP和WSH具有不同的运行模式(其他宿主亦是)。
自动类型强制
JScript是一种具有自动强制的自由类型语言。
因此,尽管实际上不同类型的值是不相等的,但对下述示例中的表达式求值都将得到true。
"100"==100;
false==0;
要核对类型与值都一致,用“严格相等”运算符(===)。
下面两个表达式的值为false:
"100"===100;
false===0;
运算符优先级
在对表达式求值时某个特定运算符的执行主要是根据运算符优先级,而不是表达式的位置。
因此,在下面的示例中,乘法将先于减法执行,尽管在该表达式中第一个出现的运算符是减法。
theRadius=aPerimeterPoint-theCenterpoint*theCorrectionFactor;
对对象使用for...in循环
当使用for...in循环对某个对象的属性进行遍历时,不必预先确定或管理将要指定给该循环计数器变量的对象字段的顺序。
此外,在该语言的不同实现方案中该顺序可能会不一样。
with关键字
with语句可以方便地用来引用某个特定对象中已有的属性,但是不能用来给对象添加属性。
要给对象创建新的属性,必须明确地引用该对象。
this关键字
尽管可以在对象的定义范围内使用this关键字来引用该对象本身,但是当函数不是该对象的定义时,就不能象普通情况那样使用this或类似的关键字来引用当前的执行函数。
如果该函数被指定为某个对象的方法,则可以在该函数内使用this关键字来引用该对象。
编写一个脚本,该脚本在IE中写脚本
当解释程序遇到标记时会终止当前脚本。
要显示""本身,请将其改写为至少两个字符串,例如"",这样就可以在输出语句中将其连接在一起。
IE中的隐式窗口引用
由于同时可以打开多个窗口,任何隐式的窗口引用都被指向当前窗口。
对于其他窗口必须使用显式引用。
条件编译
使用条件编译可以使用Jscript语言的新特性并且与不支持该特性的老版本兼容。
用@cc_on语句、@if或@set语句来激活条件编译。
条件编译的某些典型用途包括使用Jscript中的新特性、在脚本中嵌入调试支持以及跟踪代码的运行。
一般将条件编译代码放在注释中,所以不能理解条件编译的宿主(如NetscapeNavigator)就忽略了条件编译。
下面是一个示例。
/*@cc_on@*/
/*@if(@_jscript_version>=4)
alert("JScriptversion4orbetter");
@else@*/
alert("Youneedamorerecentscriptengine.");
/*@end@*/
本示例使用了特殊的注释分隔符,该分隔符只有在@cc_on语句激活条件编译时才使用。
不支持条件编译的脚本引擎只能看到一个需要更新脚本引擎的信息。
条件编译变量
下面是条件编译可用的预定义变量。
如果变量不是true,就不被定义或者作为NaN处理。
变量
描述
@_win32
在Win32系统上运行为true。
@_win16
在Win16系统上运行为true。
@_mac
在AppleMacintosh系统上运行为true。
@_alpha
在DECAlpha处理器上运行为true。
@_x86
在Intel处理器上运行为true。
@_mc680x0
在Motorola680x0处理器上运行为true。
@_PowerPC
在MotorolaPowerPC处理器上运行为true。
@_jscript
永远为true。
@_jscript_build
包含Jscript脚本引擎创建号。
@_jscript_version
包含以major、minor为格式的Jscript版本号。