| 文章索引 |
|---|
| JScript教程高级篇 |
| JScript递归 |
| JScript变量范围 |
| Jscript中复制、传递和比较数据 |
| JScript中使用数组 |
| JScript与特殊字符 |
| JScript脚本问题解答 |
| Jscript条件编译 |
| JScript条件编译变量 |
| JScript在浏览器中显示信息 |
| JScript使用警告、提示和确认 |
| 所有页面 |
在JScript教程的基础篇中我们介绍了什么是JScript?以及怎样编写JScript代码、JScript的数据类型、JScript的运算符、Jscript脚本控制程序的流程、JScript函数、Jscript保留字、JScript创建自己的对象、JScript内部对象等内容。本篇文章继续前面的内容,介绍的是JScript教程的高级篇内容。
使用构造函数来创建对象
构造函数是一个函数,调用它来例示并初始化特殊类型的对象。可以使用 new 关键字来调用一个构造函数。 下面给出了使用构造函数的新示例。
var myObject = new Object(); // 创建没 有属性的通用对象。通过构造函数将一个参数作为特定的 this 关键字的值传递给新创建的空对 象。然后构造函数负责为新对象执行适应的初始化(创建属性并给出其初始值)。完成后,构 造函数返回它所构造的对象的一个参数。
var myBirthday = new Date(1961, 5, 10); // 创建一个 Date 对象。
var myCar = new Car(); // 创建一个用户定义的对象,并初始化其属性。
编写构造函数
可以使用 new 运算符结合像 Object()、Date() 和 Function() 这样的预定义的构造函数来创建对象并对其初始化。面向对象的 编程其强有力的特征是定义自定义构造函数以创建脚本中使用的自定义对象的能力。创建了自 定义的构造函数,这样就可以创建具有已定义属性的对象。下面是自定义函数的示例(注意 this 关键字的使用)。
function Circle (xPoint, yPoint, radius) { this.x = xPoint; // 圆心的 x 坐标。
this.y = yPoint; // 圆心的 y 坐标。
this.r = radius; // 圆 的半径。 } 调用 Circle 构造函数时,给出圆心点的值和圆的半径(所有这些元素 是完全定义一个独特的圆对象所必需的)。结束时 Circle 对象包含三个属性。下面是如何例示 Circle 对象。
var aCircle = new Circle(5, 11, 99);
使用原型来创建对象
在编写构造函数时,可以使用原型对象(它本身是所有构造函数的一个属性) 的属性来创建继承属性和共享方法。原型属性和方法将按引用复制给类中的每个对象,因此它 们都具有相同的值。可以在一个对象中更改原型属性的值,新的值将覆盖默认值,但仅在该实 例中有效。属于这个类的其他对象不受此更改的影响。下面给出了使用自定义构造函数的示例 ,Circle(注意 this 关键字的使用)。
Circle.prototype.pi = Math.PI; function ACirclesArea () {
return this.pi * this.r * this.r; // 计算圆面积的公式为 ? r2。
} Circle.prototype.area = ACirclesArea; // 计算圆面积的函数现在是 Circle Prototype 对象的一个方法。
var a = ACircle.area(); // 此为如何在 Circle 对象上调用面 积函数。 使用这个原则,可以给预定义的构造函数(都具有原型对象)定义附 加属性。例如,如果想要能够删除字符串的前后空格(与 VBScript 的 Trim 函数类似),就可以给 String 原型对象创建自己的方法。
// 增加 一个名为 trim 的函数作为
// String 构造函数的原型对象的一个方法。
String.prototype.trim = function() { // 用正则表达式将前后空格
// 用空字符串替代。
return this.replace(/ (^\s*)|(\s*$)/g, ""); } // 有空格的字符串
var s = " leading and trailing spaces "; // 显示
" leading and trailing spaces (35)" window.alert(s + " (" + s.length + ")"); // 删除前后空格
s = s.trim(); // 显示"leading and trailing spaces (27)" window.alert(s + " (" + s.length + ")");
递归 是一种重要的编程技术。该方法用于让一个函数从其内部调用其自身。一个示例就是计算阶乘 。0 的阶乘被特别地定义为 1。 更大数的阶乘是通过计算 1 * 2 * ...来求得的,每次增加 1,直 至达到要计算其阶乘的那个数。
下面的段落是用文字定义的计算阶乘的一个函数 。
“如果这个数小于零,则拒绝接收。如果不是一个整数,则将其向下舍入为相邻 的整数。如果这个数为 0,则其阶乘为 1。如果这个数大于 0,则将其与相邻较小的数的阶乘 相乘。”
要计算任何大于 0 的数的阶乘,至少需要计算一个其他数的阶乘。用来 实现这个功能的函数就是已经位于其中的函数;该函数在执行当前的这个数之前,必须调用它 本身来计算相邻的较小数的阶乘。这就是一个递归示例。
递归和迭代(循环)是 密切相关的 — 能用递归处理的算法也都可以采用迭代,反之亦然。确定的算法通常可以用几种 方法实现,您只需选择最自然贴切的方法,或者您觉得用起来最轻松的一种即可。
显然,这样有可能会出现问题。可以很容易地创建一个递归函数,但该函数不能得到一个确 定的结果,并且不能达到一个终点。这样的递归将导致计算机执行一个“无限”循环。下面就是 一个示例:在计算阶乘的文字描述中遗漏了第一条规则(对负数的处理) ,并试图计算任何负 数的阶乘。这将导致失败,因为按顺序计算 -24 的阶乘时,首先不得不计算 -25 的阶乘;然而 这样又不得不计算 -26 的阶乘;如此继续。很明显,这样永远也不会到达一个终止点。
因此在设计递归函数时应特别仔细。如果怀疑其中存在着无限递归的可能,则可以让 该函数记录它调用自身的次数。如果该函数调用自身的次数太多,即使您已决定了它应调用多 少次,就自动退出。
下面仍然是阶乘函数,这次是用 JScript 代码编写的。
// 计算阶乘的函数。如果传递了
// 无效的数值(例如小于零),
// 将返回 -1,表 明发生了错误。若数值有效,
// 把数值转换为最相近的整数,并
// 返回阶乘。
function factorial(aNumber) { aNumber = Math.floor(aNumber);
// 如果这个数不是一个整数,则向下舍 入。
if (aNumber < 0) { // 如果这个数小于 0,拒绝接收。
return -1; } if (aNumber == 0) { // 如果为 0,则其阶乘为 1。}
return 1; } else return (aNumber * factorial (aNumber - 1)); //否则,递归直至完成。 }
JScript 有两种变量范围:全局和局部。如果在任何函数定义之外声明了一个 变量,则该变量为全局变量,且该变量的值在整个持 续范围内都可以访问和修改。如果在函数定义内声明了一个变量,则该变量为局部变量。每次 执行该函数时都会创建和破坏该变量;且它不能被该函数外的任何事物访问。
像 C++ 这样的语言也有“块范围”。在这里,任何一对“{}”都定义新的范围。JScript 不支持块范围。
一个局部变量的名称可以与某个全局变量的名称相同,但这是完全不同和独立的 两个变量。因此,更改一个变量的值不会影响另一个变量的值。在声明局部变量的函数内,只 有该局部变量有意义。
var aCentaur = "a horse with rider,"; // aCentaur 的全局定义。
// JScript 代码,为简洁起见有省略。
function antiquities() // 在这个函数中声明了一个 局部 aCentaur 变量。
{ // JScript 代码,为简洁起见有省略。
var aCentaur = "A centaur is probably a mounted Scythian warrior"; // JScript 代码,为简洁起见有省略。
aCentaur += ", misreported; that is, "; // 添加到局部变量。
// JScript 代码,为简洁起见有省略。 } // 函数结束。
var nothinginparticular = antiquities(); aCentaur += " as seen from a distance by a naive
innocent."; /* 在函数内,该变量的值为 "A centaur is probably a mounted Scythian warrior,
misreported; that is, ";在函数外,该变量的值为这句话的其余部分: "a horse with rider, as
seen from a distance by a naive innocent." */
很重要的一点是注意变量是否是 在其所属范围的开始处声明的。有时这会导致意想不到的情况。
tweak(); var aNumber = 100; function tweak() { var newThing = 0; // 显式声明 newThing 变量。
// 本语 句将未定义的变量赋给 newThing,因为已有名为 aNumber 的局部变量。
newThing = aNumber; //下一条语句将值 42 赋给局部的 aNumber。aNumber = 42; if (false) {
var aNumber; // 该语句永远不会执行。 aNumber = 123; // 该语句永远不会执行。
} // 条 件语句结束。 } // 该函数定义结束。 当 JScript 运行函数时,首先查找所有的 变量声明,
var someVariable;
并以未定义的初始值创建变量。如果变 量被声明时有值,
var someVariable = "something";
那么该变量仍以 未定义的值初始化,并且只有在运行了声明行时才被声明值取代,假如曾经被声明过。
JScript 在运行代码前处理变量声明,所以声明是位于一个条件块中还是其他某些结构 中无关紧要。JScript 找到所有的变量后立即运行函数中的代码。如果变量是在函数中显式声明 的 — 也就是说,如果它出现于赋值表达式的左边但没有用 var 声明 — 那么将把它创建为全局 变量。
在 JScript 中,对数据的处理取决于该数据的类型。
按值和按引用的 比较
Numbers 和 Boolean 类型的值 (true 和 false) 是按值来复制、传递和比较的。当按值复制或传递时,将在计算机内 存中分配一块空间并将原值复制到其中。然后,即使更改原来的值,也不会影响所复制的值( 反过来也一样),因为这两个值是独立的实体。
对象、数组以及函数是按引用来 复制、传递和比较的。 当按地址复制或传递时,实际是创建一个指向原始项的指针,然后就像 拷贝一样来使用该指针。如果随后更改原始项,则将同时更改原始项和复制项(反过来也一样 )。实际上只有一个实体;“复本”并不是一个真正的复本,而只是该数据的又一个引用。
当按引用比较时,要想比较成功,两个变量必须参照完全相同的实体。例如,两个不 同的 Array 对象即使包含相同的元素也将比较为不相等。要想比较成功,其 中一个变量必须为另一个的参考。要想检查两个数组是否包含了相同的元素,比较 toString() 方法的结果。
最后,字符串是按引用复制和传递的, 但是是按值来比较的。请注意,假如有两个 String 对象(用 new String("something") 创建的),按引用比较它们,但是,如果其中一个 或者两者都是字符串值的话,按值比较它们。
注意 鉴于 ASCII和 ANSI 字符集的构造方法,按序 列顺序大写字母位于小写字母的前面。例如 "Zoo" 小于 "aardvark"。如果想执行不区分大小写 的匹配,可以对两个字符串调用 toUpperCase() 或 toLowerCase() 。
传递参数给函数
按值传递一个参数给函数就是制作该参 数的一个独立复本,即一个只存在于该函数内的复本。即使按引用传递对象和数组时,如果直 接在函数中用新值覆盖原先的值,在函数外并不反映新值。只有在对象的属性或者数组的元素 改变时,在函数外才可以看出。
例如(使用 IE 对象模式):
// 本代 码段破坏(覆盖)其参数,所以 // 调用代码中反映不出变化。
function Clobber(param) { // 破坏参数;在调用代码中 // 看不到。
param = new Object();
param.message = "This will not work"; } // 本段代码改变参数的属性, // 在调用代码中可看到属性改变。
function Update(param) { // 改变对象的属性; // 可从调用代码中看到改变。
param.message = "I was changed"; } // 创建一个对象,并赋给一个属性。
var obj = new Object(); obj.message =
"This is the original"; // 调用 Clobber,并输出 obj.message。注意,它没有发生变化。
Clobber (obj); window.alert(obj.message); // 仍然显示 "This is the original"。
// 调用 Update,并输出 obj.message。注意,它已经被改变了。
Update(obj); window.alert(obj.message); // 显示 "I was changed"。
检验数据
当按值进行检验时,是比较两个截然不同的项 以查看它们是否相等。通常,该比较是逐字节进行的。当按引用进行检验时,是看这两项是否 是指向同一个原始项的指针。如果是,则比较结果是相等;如果不是,即使它们每个字节都包 含完全一样的值,比较结果也为不相等。
按引用复制和传递字符串能节约内存; 但是由于在字符串被创建后不能进行更改,因此可以按值进行比较。这样可以检查两个字符串 是否包含相同的内容,即使它们是完全独立产生的。
数组下标
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 循环。特殊字符@import url (../html-vss/msdnie4a.css);
JScript 提供了一些特殊字符,允许在字符串中包括一些无法直接键入的字符。 每个字符都以反斜杠开始。反斜杠是一个转义字符,表示 JScript 解释器下面的字符为特殊字 符。
| 转义 序列 | 字符 |
|---|---|
| \b | 退格 |
| \f | 走 纸换页 |
| \n | 换行 |
| \r | 回车 |
| \t | 横向跳格 (Ctrl-I) |
| \' | 单引号 |
| \" | 双引号 |
| \\ | 反斜杠 |
请注意, 由于反斜杠本身用作转义符,因此不能直接在脚本中键入一个反斜杠。如果要产生一个反斜杠 ,必须一起键入两个反斜杠 (\\)。
document.write('The image path is
C:\\webstuff\\mypage\\gifs\\garden.gif.'); document.write('The caption reads, "After the snow of
\'97. Grandma\'s house is covered."');如果不够细致,任何编程语言都有一些可 能发生错误的地方,而且每种语言都有其特殊之处。例如,对于 null 值: JScript 中这个值与 C 或 C++ 语言中的 Null 值所起的作用是不一样的。
下面提供了一些在编写 JScript 脚本时可能遇到的问题。
语法错误
由于编程语言中的语法比 自然语言的语法要严格得多,因此在编写脚本时对细节应倍加关注。例如,如果您本意是将字 符串作为某个参数,但是在键入时忘了使用引号引起来,就会产生问题。
脚本解释 顺序
对 JScript 的解释是 Web 浏览器的 HTML 语法分析处理的一部分。因此,如 果在文档的 <HEAD> 标识中放置了一个脚本,则将在检查所有的 <BODY> 标识之前 加以解释。如果在 <BODY> 标识中将创建对象,但由于在分析处理 <HEAD> 标识时 这些对象尚不存在,因而不能被脚本操作。
注意: 本情况特定于 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 中写脚本
当解释程序遇到</SCRIPT>标记时会终止 当前脚本。要显示"</SCRIPT>" 本身,请将其改写为至少两个字符串,例如 "</SCR" 和 "IPT>",这样就可以在输出语句中将其连接在一起。
IE 中的隐式窗口引用
由于同时可以打开多个窗口,任何隐式的窗口引用都被指向当前窗口。对于其他窗口 必须使用显式引用。
使用条件编译可以使用 Jscript 语言的新特性并且与不支持该特性的老版本兼容 。
用 @cc_on 语句、@if 或 @set 语句来激活条件编译。条件编译的某些典型用途包括使用 Jscript 中的 新特性、在脚本中嵌入调试支持以及跟踪代码的运行。
一般将条件编译代码放在 注释中,所以不能理解条件编译的宿主(如 Netscape Navigator)就忽略了条件编译。下面是 一个示例。
/*@cc_on @*/ /*@if (@_jscript_version >= 4) alert("JScript version 4 or better");
@else @*/ alert("You need a more recent script engine."); /*@end @*/ 本示例使用了特殊的注释分隔符,该分隔符只有在 @cc_on 语句激 活条件编译时才使用。不支持条件编译的脚本引擎只能看到一个需要更新脚本引擎的信息。
下面是条件编译可用的预定义变量。如果变量不是 true,就不被定义或者作为 NaN 处理。
| 变量 | 描述 |
|---|---|
| @_win32 | 在 Win32 系统上运行为 true。 |
| @_win16 | 在 Win16 系统上运行为 true。 |
| @_mac | 在 Apple Macintosh 系统上运行 为 true。 |
| @_alpha | 在 DEC Alpha 处理器上运行为 true。 |
| @_x86 | 在 Intel 处理器上运行为 true。 |
| @_mc680x0 | 在 Motorola 680x0 处理器上运行为 true。 |
| @_PowerPC | 在 Motorola PowerPC 处理器上运行为 true。 |
| @_jscript | 永远为 true。 |
| @_jscript_build | 包含 Jscript 脚本引擎创建号。 |
| @_jscript_version | 包含以 major、 minor 为格式的 Jscript 版本号。 |
Microsoft JScript 提供了两种方式来在浏览器中直接显示数据。可以使用 write( ) 和 writeln( ),这两个函数是 document 对象的方法。也可以在浏览器中以表格的方式显示信息,以及用 警告、提示和确认 消息框来显示信息。
使 用document.write( ) 和 document.writeln( )
显示信息最常用的方式是 document 对象的 write( ) 方法。该方法用一个字符串作为其参数,并在浏览器中显示 。该字符串可以是普通文本或 HTML。
字符串可以用单引号或双引号引起来。这 样可以引用那些包含引号或撇号的内容。
document.write("Pi is approximately equal to " + Math.PI); document.write( ); 注意: 下面的简单函数可以避免在浏览器中显示信息时不得不键入 "document.write"。该函数不能告知要显示的信息是否未定义,而是发布给命令 "w();",该命令 将显示一个空行。
function w(m) { // 编写函数。 m = "" + m + ""; // 确保变量 m 是 一个字符串。
if ("undefined" != m) { // 判别是否为空或其它未定义的项。
document.write(m);
} document.write("<br>"); } w('<IMG src="/horse.gif">'); w();
w("This is an engraving of a horse."); w(); writeln( ) 方法与 write( ) 方法 几乎一样,差别仅在于是前者将在所提供的任何字符串后添加一个换行符。在 HTML 中,这通 常只会在后面产生一个空格;不过如果使用了 <PRE> 和 <XMP> 标识,这个换行符会 被解释,且在浏览器中显示。
在调用 write( ) 方法时,如果该 文档不处于在调用 write( ) 方法时的打开和分析的过程中,该方法将打开并 清除该文档,所以它可能是有危险的。该示例显示了一个每隔一分钟就显示时间的脚本,但是 在第一次显示后由于它从过程中将自己清除,因此会导致失败。
<HTML> <HEAD> <SCRIPT LANGUAGE="JScript"> function singOut() {
var theMoment = new Date(); var theHour = theMoment.getHours();
var theMinute = theMoment.getMinutes();
var theDisplacement = (theMoment.getTimezoneOffset() / 60); theHour -= theDisplacement;
if (theHour > 23) { theHour -= 24 } document.write(theHour + " hours, " + theMinute + " minutes,
Coordinated Universal Time."); window.setTimeout("singOut();", 60000); } </SCRIPT>
</HEAD> <BODY> <SCRIPT> singOut(); </SCRIPT> </BODY> </HTML> 如果使用 window 对象的 alert() 方法而不是 document.write(),则该脚本可以运行。
window.alert(theHour + " hours, " + theMinute + " minutes, Coordinated Universal Time.");
window.setTimeout("singOut();", 60000); }
清除当前文档
document 对象的 clear() 方法将清空当前文档。该方法也将清除您的脚本(随文档的其他部分 一起),因此要特别注意该方法的使用方式及在什么时候使用该方法。
document.clear();
可以使用警告、确认和提示消息框来 获得用户的输入。这些消息框是 window 对象的接口方法。由于 window 对象位于对象层次的顶层,因此实际应用中不必使用这些消息框的 全名(例如 "window.alert()"),不过采用全名是一个好注意,这样有助于您记住这些消息框属 于哪个对象。
警告消息框
alert 方法有一个参数, 即希望对用户显示的文本字符串。该字符串不是 HTML 格式。该消息框提供了一个“确定”按钮 让用户关闭该消息框,并且该消息框是模式对话框,也就是说,用户必须先关闭该消息框然后 才能继续进行操作。
window.alert("欢迎!请按“确定”继续。"); 确认消息 框
使用确认消息框可向用户问一个“是-或-否”问题,并且用户可以选择单击“确定 ”按钮或者单击“取消”按钮。confirm 方法的返回值为 true 或 false。该消息框也是模式对话框:用户必须在响应该对话框(单击一个按 钮)将其关闭后,才能进行下一步操作。
var truthBeTold = window.confirm("单击“确 定”继续。单击“取消”停止。");
if (truthBeTold) { window.alert("欢迎访问我们的 Web 页!"); } else window.alert("再见啦!"); 提示消息框
提示消息框提供了一个文本字 段,用户可以在此字段输入一个答案来响应您的提示。该消息框有一个“确定”按钮和一个“取消” 按钮。如果您提供了一个辅助字符串参数,则提示消息框将在文本字段显示该辅助字符串作为 默认响应。否则,默认文本为 "<undefined>"。
与alert( ) 和 confirm( ) 方法类似,prompt 方法也将显示一个模式消 息框。用户在继续操作之前必须先关闭该消息框
var theResponse = window.prompt(" 欢迎?","请在此输入您的姓名。"); (本文结束)