什么是 JavaScript?

JScript 是 Microsoft 公司对 ECMA 262 语言规范(ECMAScript 编辑器 3)的一种实现。除了少数例外(为了保持向后兼容),JScript 完全实现了 ECMA 标准。本概述的目的就是引导您学习使用 JScript。

使用 JavaScript

JScript 是一种解释型的、基于对象的脚本语言。尽管与 C++ 这样成熟的面向对象的语言相比,JavaScript 的功能要弱一些,但对于它的预期用途而言,JavaScript 的功能已经足够大了。

JScript 不是其他语言的精简版(例如,它只是与 Java 有点模糊而间接的关系),也不是任何事物的简化。不过,它有其局限性。例如,您不能使用该语言来编写独立运行的应用程序,并且没有对读写文件的内置支持。此外,JavaScript 脚本只能在某个解释器或“宿主”上运行,如 Active Server Pages(ASP)、Internet 浏览器或者 Windows 脚本宿主。

JavaScript 是一种宽松类型的语言。宽松类型意味着您不必显式定义变量的数据类型。事实上 JavaScript 更进一步。您无法在JavaScriot上明确地定义数据类型。此外,在大多数情况下,JavaScript 将根据需要自动进行转换。例如,如果将一个数值添加到由文本组成的某项(一个字符串),该数值将被转换为文本。

JavaScript 的变量

任何编程语言中,用一块数据量化一个概念。

变量声明

变量在脚本中的第一次出现是在声明中。变量在第一次用到时就设置于内存中,便于后来在脚本中引用。使用变量之前先进行声明。可以使用 var 关键字来进行变量声明。

var count; // 单个声明。

var count, amount, level; // 用单个 var 关键字声明的多个声明。

var count = 0, amount = 100; // 一条语句中的变量声明和初始化。

如果在 var 语句中没有初始化变量,变量自动取 JavaScript 值 undefined。尽管并不安全,但声明语句中忽略 var 关键字是合法的 JavaScript 语法。这时,JavaScript 解释器给予变量全局范围的可见度。当在过程级中声明一个变量时,它不能用于全局范围;这种情况下,变量声明必须var 关键字。

变量命名

变量名称是一个标识符。JavaScript 中,用标识符来:

命名变量,

命名函数,

给出循环的标签。

JavaScript 是一种区分大小写的语言。因此变量名称 myCounter 和变量名称 mYCounter 是不一样的。变量的名称可以是任意长度。创建合法的变量名称应遵循如下规则:

第一个字符必须是一个 ASCII 字母(大小写均可),或一个下划线(_)。注意第一个字符不能是数字。

后续的字符必须是字母、数字或下划线。

变量名称一定不能是 保留字

下面给出合法变量名称的一些示例:

_pagecount 

Part9 

Number_Items 

下面给出无效变量名称的一些示例:

99Balloons // 不能以数字开头。

Smith&Wesson // “与”符号(&)字符用于变量名称是无效的。

当要声明一个变量并进行初始化,但又不想指定任何特殊值,可以赋值为 JavaScript 值 null。下面给出示例。

var bestAge = null;

var muchTooOld = 3 * bestAge; // muchTooOld 的值为 0

如果声明了一个变量但没有对其赋值,该变量存在,其值为JavaScript 值 undefined。下面给出示例。

var currentCount;

var finalCount = 1 * currentCount; // finalCount 的值为 NaN,因为 currentCount undefined

注意在 JavaScript 中 nullundefined 的主要区别是 null 的操作象数字 0,而 undefined 的操作象特殊值NaN (不是一个数字)。对 null 值和 undefined 值作比较总是相等的。

可以不用 var 关键字声明变量,并赋值。这就是隐式声明。

noStringAtAll = ""; // 隐式声明变量 noStringAtAll

不能使用未经过声明的变量。

var volume = length * width; // 错误 length width 并不存在。

强制转换

表达式中操作项的数据类型相同时 JavaScript 解释器才能对其求值。如果表达式不经过强制转换就试图对两个不同的数据类型(如一个为数字,另一个为字符串)执行运算,将产生错误结果。但在 JavaScript 中情况就不同了。

JScript 是一种自由类型的语言。它的变量没有预定类型(相对于强类型语言,如 C++)。相反,JavaScript 变量的类型相应于他们包含的值的类型。这种操作的好处是能将值作为另一类型处理。

在 JavaScript 中,可以对不同类型的值执行运算,不必担心 JavaScript 解释器产生异常。相反,JavaScript 解释器自动将数据类型之一改变(强制转换)为另一种数据类型,然后执行运算。例如:

var x = 2000; // 一个数字。

var y = "Hello"; // 一个字符串。

x = x + y; // 将数字强制转换为字符串。

document.write(x); // 输出 2000Hello

JavaScript 的数据类型

JavaScript 有三种主要数据类型、两种复合数据类型和两种特殊数据类型。

主要(基本)数据类型是:

字符串

数值

布尔

复合(引用)数据类型是:

对象

数组

特殊数据类型是:

Null

Undefined

字符串数据类型

一个字符串值是排在一起的一串零或零以上的 Unicode 字符(字母、数字和标点符号)。字符串数据类型用来表示 JavaScript 中的文本。脚本中可以包含字符串文字,这些字符串文字放在一对匹配的的单引号或双引号中。字符串中可以包含双引号,该双引号两边需加单引号,也可以包含单引号,该单引号两边需加双引号。下面是字符串的示例:

"Happy am I; from care I’m free!"

'"Avast, ye lubbers!" roared the technician.' 

"42"

'c'

注意:JScript 中没有表示单个字符的类型(如 C++ 的 char)。要表示 JavaScript 中的单个字符,应创建一个只包含一个字符的字符串。包含零个字符("")的字符串是空(零长度)字符串。

数值数据类型

在 JavaScript 中整数和浮点值没有差别;JScript 数值可以是其中任意一种(JavaScript 内部将所有的数值表示为浮点值)。

整型值

整型值可以是正整数,负整数和 0。可以用 10 进制,8 进制和 16 进制来表示。在 Jscript 中大多数字是用十进制表示的。加前缀“0”表示 8 进制的整型值,只能包含 0 到 7 的数字。前缀为“0”同时包含数字“8”或“9”的数被解释为十进制数。

加前缀“0x”(零和x|X)表示 16 进制整型值。可以包含数字 0 到 9,以及字母 A 到 F(大写或小写)。使用字母 A 到 F 表示十进制 10 到 15 的单个数字。就是说 0xF 与 15 相等,同时 0x10 等于 16。

八进制和十六进制数可以为负,但不能有小数位,同时不能以科学计数法(指数)表示。

浮点值

浮点值为带小数部分的数。也可以用科学计数法来表示。这就是说,大写或小写“e”用来表示 10 的次方。Jscript用数值表示的八字节 IEEE754 浮点标准。这意味着数字最大可以到±1.7976931348623157x10308,最小到±5x10-324。以“0”开始且包含小数点的数字被解释为小数浮点数。

注意:以“0x”或“00”开始并包含小数点的数将发生错误。以下是 Jscript 中数字的例子。

另外,JScript包含特殊值数字。它们是:

NaN (不是数)。当对不适当的数据进行数学运算时使用,例如字符串或未定义值。

正无穷大。在JavaScript中如果一个正数太大的话使用它来表示。

负无穷大。在JavaScript中如果一个负数太大的话使用它来表示。

正0和负0。JavaScript区分正0和负0。

Boolean数据类型

尽管字符串和数字类型可以有无数不同的值,boolean 数据类型却只有两个值。它们是文字 true false。Boolean值是一个真值,它表示一个状态的有效性(说明该状态为真或假)。

脚本中的比较通常得到一个 Boolean 结果。考虑下一行 JavaScript 代码。

y = (x == 2000);

这里要比较变量 x 的值是否与数字 2000 相等。如果相等,比较的结果为 Boolean 值 true,并将其赋给变量 y。如果x与2000不等,则比较的结果为boolean值false

Boolean值在结构控制中尤其有用。可以将直接创建 boolean 值的比较与用使用该 boolean 值的语句相组合。考虑下面的JavaScript代码范例。

if (x == 2000)
    z = z + 1;
else
    x = x + 1;

当 boolean 值为 true 时,JavaScript 中的 if/else 语句执行一个操作(这样,z = z + 1),而当 boolean 值为 false 时执行另一个操作(x = x + 1)。

可以使用任意表达式作比较表达式。任何值为0、null、未定义或空字符串的表达式被解释为 false。其他任意值的表达式解释为 true。例如,可以使用如下表达式:

if (x = y + z) // 这可能不是想要的结果如下!

注意上面的代码并不检查 x 是否与 y+z 相等,因为仅使用了一个等号(赋值)。相反的,上面的代码将 y+z 赋给变量 x,然后检查整个表达式的值是否为零。要检查 x 是否与 y+z 相等,使用如下代码。

if (x == y + z) // 这与上面的代码不同!

Null 数据类型

在 JsvaScript 中数据类型 null 只有一个值:null。关键字 null 不能用作函数或变量的名称。

包含 null 的变量包含“无值”或“无对象”。换句话说,该变量没有保存有效的数、字符串、boolean、数组或对象。可以通过给一个变量赋 null 值来清除变量的内容。

请注意,在 JavaScript 中,null 与 0 不相等(与在 C 和 C++ 中不同)。同时应该指出的是,JavaScript中 typeof 运算符将报告 null 值为 Object 类型,而非类型 null。这点潜在的混淆是为了向下兼容。

Undefined 数据类型

如下情况使返回 undefined 值:

对象属性不存在,

声明了变量但从未赋值。

注意不能通过与 undefined 做比较来测试一个变量是否存在,虽然可以检查它的类型是否为“undefined”。在以下的代码范例中,假设程序员想测试是否已经声明变量 x :

// 这种方法不起作用
if (x == undefined)
    // 作某些操作

// 这个方法同样不起作用- 必须检查
// 字符串 "undefined"
if (typeof(x) == undefined)
    // 作某些操作

// 这个方法有效
if (typeof(x) == "undefined")
    // 作某些操作

考虑将 undefined 值与null做比较。

someObject.prop == null;

如下情况时,比较的结果为 true

如果属性 someObject.prop 包含 null 值,

如果属性 someObject.prop 不存在。

要检查一个对象属性是否存在,可以使用新的 in 运算符:

if ("prop" in someObject)
// someObject 有属性 'prop'

JavaScript 的运算符

JScript 具有全范围的运算符,包括算术、逻辑、位、赋值以及其他某些运算符。

== (相等)与 === (严格相等)的区别在于恒等运算符在比较前强制转换不同类型的值。例如,恒等对字符串 "1" 与数值 1 的比较结果将为 true。而严格相等不强制转换不同类型的值,因此它认为字符串 "1" 与数值 1 不相同。

基本的字符串、数值和布尔值是按值比较的。如果它们的值相同,比较结果为相等。对象(包括ArrayFunctionStringNumberBooleanError、Date以及 RegExp 对象)按引用比较。即使这些类型的两个变量具有相同的值,只有在它们正好为同一对象时比较结果才为 true。

// 具有相同值的两个基本字符串。
var string1 = "Hello";
var string2 = "Hello";

// 具有相同值的两个 String 对象。
var StringObject1 = new String(string1);
var StringObject2 = new String(string2);

// 比较结果为 trueif (string1 == string2)
     // 执行某些命令(将要运行的)。

// 比较结果为 falseif (StringObject1 == StringObject2)
    //执行某些命令(不会运行)。

// 要比较 String 对象的值, 
//  toString() 或者 valueOf() 方法。
if (StringObject1.valueOf() == StringObject2)
     //执行某些命令(将要运行的)。

控制程序的流程

JavaScript 脚本中的语句一般是按照写的顺序来运行的。这种运行称为顺序运行,是程序流的默认方向。

与顺序运行不同,另一种运行将程序流转换到脚本的另外的部分。也就是,不按顺序运行下一条语句,而是运行另外的语句。

要使脚本可用,该控制的转换必须以逻辑方式执行。程序控制的转换是基于一个“决定”,这个“决定”结果是真或假(返回 Boolean 型 true false)。 创建一个表达式,然后测试其是否为真。主要有两种程序结构实现本功能。

第一种是选择结构。用来指明两种程序流方向,在程序中创建一个交叉点(像岔路)。在 JavaScript 中有四种选择结构可用。

单一选择结构(if),

二路选择结构(if/else),

内联三元运算符 ?:

多路选择结构(switch)。 

第二种类型的程序控制结构是循环结构。使用循环结构来指明当某些条件保持为真时要重复的动作。当控制语句的条件得到满足时(通常在某些迭代的特定数字后),控制跳过循环结构传递到下条语句。在 JavaScript 中有四种循环结构可用。

在循环的开头测试表达式(while),

在循环的末尾测试表达式(do/while),

对对象的每个属性都进行操作(for/in),

由计数器控制的循环(for)。

通过嵌套和堆栈选择、循环控制结构,可以创建相当复杂的脚本。

第三种形式的结构程序流由意外处理给出,本文档不作讨论。

使用条件语句

JavaScript 支持 ifif...else 条件语句。在 if 语句中将测试一个条件,如果该条件满足测试,执行相关的 JavaScript 编码。在 if...else 语句中,如果条件不满足测试,则将执行不同的代码。最简单的 if 语句格式可以在一行中写完,不过更常见的是多行的 ifif...else 语句。

下述示例演示了使用 ifif...else 语句的各种可能的语法。第一个示例演示了最简单的布尔测试。当(且仅当)括号之间的项的值为(或者可被强制转换为) true 时,if 后续的语句或语句块才会被执行。

// smash() 函数是在该代码的其他地方定义的。
// 布尔测试,看 newShip 是否为 trueif (newShip)
   smash(champagneBottle,bow); 

// 在本示例中,除非两个条件都为真,否则该测试将不会被满足。
if (rind.color == "deep yellow " && rind.texture == "large and small wrinkles")
{
   theResponse = ("Is it a Crenshaw melon?");
}

// 在本示例中,只要任何一个条件为真,则测试即会满足。
var theReaction = "";
if ((dayOfWeek == "Saturday") || (dayOfWeek == "Sunday"))
{
   theReaction = ("I'm off to the beach!");
}
else
{
   theReaction = ("Hi ho, hi ho, it's off to work I go!");
}

条件运算符

JavaScript 也支持隐式的条件格式。该格式在要测试的条件后使用一个问号(而不是在条件前的 if )。它也指定两个可选项,一个在满足条件时使用,另一个在条件不满足时使用。这两个选择项之间必须用一个冒号隔开。

var hours = "";

// 下面的代码指定 hours 是包含 theHour 的内容,
// 还是包含 theHour - 12 的内容。

hours += (theHour >= 12) ? " PM" : " AM";

如果要一起测试多个条件,并且知道某个条件比其他条件更可能满足或不满足测试,可以使用称为“短路计算”的特性来加速脚本的运行速度。当 JavaScript 计算逻辑表达式时,只计算要得到结果所需的子表达式。

例如,如果有一个“与”表达式,如 ((x == 123) && (y == 42)),JavaScript 首先检查 x 是否为 123。如果不是,即使 y 等于 42,整个表达式的值也不可能为 true。因此,并不对 y 作测试,Jscript 返回 false 值。

类似地,如果多个条件中只要有一个为真(使用 || 运算符),则当任何一个条件满足该测试时测试则停止。如果要测试的条件包括函数调用或其他复合表达式,这种处理方式就有效。出于此种想法,写 OR 表达式时,先写最有可能为 true 的条件。写 AND 表达式时,先写最有可能为 false 的条件。

以这种方式设计脚本的好处的一个示例是:在下例中如果 runfirst() 返回 0 或 false, 则不会运行 runsecond()

if ((runfirst() == 0) || (runsecond() == 0)) {
    // 若干代码。
}

使用循环

有多种方式来重复执行一条语句或语句块。通常重复执行被称为循环重复。重复只是循环的一个运行。典型情况是用一个变量测试来进行控制,每执行一次循环变量的取值都会更改。JavaScript 支持四种循环: for 循环、 for...in 循环、 while 循环、 do...while 循环。

使用 for 循环

for 语句指定了一个计数器变量,一个测试条件,以及更新该计数器的操作。在每次循环的重复之前,都将测试该条件。如果测试成功,将运行循环中的代码。如果测试不成功,不运循环中的代码,程序继续运行紧跟在循环后的第一行代码。在执行该循环后,计算机变量将在下一次循环之前被更新。

如果循环条件永不会满足,则不执行该循环。如果测试条件始终满足,则将导致无限循环。在有些情况下,前者可能是合乎需要的,而后者几乎没有用处,因此在编写循环条件时一定要注意。

/*
更新表达式 (下例中的 "icount++")将在循环结束时被执行,即在构成循环主体的语句块被执行后,在测试条件之前。
*/

var howFar = 10;  // 将循环次数限制为 10var sum = new Array(howFar);  // 创建一个称为 sum 并具有 10 个成员的数组,这 10 个成员从 0  9var theSum = 0;
sum[0] = 0;

for(var icount = 0; icount < howFar; icount++)  {        // 在本例中将从 0  9 进行计数。
theSum += icount;
sum[icount] = theSum;
}

var newSum = 0;
for(var icount = 0; icount > howFar; icount++)  {        // 该循环根本不会被执行,因为 icount 不大于 howFarnewSum += icount;
}

var sum = 0;
for(var icount = 0; icount >= 0; icount++)  {        // 这是一个无限循环。
sum += icount;
}

使用 for...in 循环

JavaScript 提供了一种特别的循环方式来遍历一个对象的所有用户定义的属性或者一个数组的所有元素。for...in 循环中的循环计数器是一个字符串,而不是数字。它包含当前属性的名称或者当前数组元素的下标。

下面的代码范例应在 Internet 浏览器中运行,因为它使用 alert 方法,该方法不属于 JavaScript。

// 创建具有某些属性的对象
var myObject = new Object();
myObject.name = "James";
myObject.age = "22";
myObject.phone = "555 1234";

// 枚举(循环)对象的所有属性
for (prop in myObject)
{
    // 显示 "The property 'name' is James",等等。
    window.alert("The property '" + prop + "' is " + myObject[prop]);
}

尽管 for...in 循环看起来像 VBScript 的 For Each...Next 循环,其实并不一样。JavaScript 的 for...in 循环重复JavaScript 对象所有的属性。VBScript 的 For Each...Next 循环重复集合中的所有项目。要循环 JavaScript 中的所有集合,需要用 Enumerator 对象。尽管某些对象(像 Internet 浏览器中的那些)支持 VBScript 的 For Each...Next 和 Jscript 的 for...in 循环,但多数对象并不都支持。

使用 while 循环

while 循环相似于 for 循环。其不同之处是 while 循环没有内置的计数器或更新表达式。如果希望控制语句或语句块的循环执行,需要不只是“运行该代码 n 次”,而是更复杂的规则,用 while 循环。下面的示例使用 Internet 浏览器对象模型和 while 循环来询问用户一个简单的问题。

var x = 0;
while ((x != 42) && (x != null))
{
    x = window.prompt("What is my favourite number?", x);
}

if (x == null)
    window.alert("You gave up!");
else
    window.alert("Yep - it's the Ultimate Answer!");

注意 由于 while 循环没有显式的内置计数器变量,因此比其他类型的循环更容易产生无限循环。此外,由于不易发现循环条件是在何时何地被更新的,很容易编写一个实际上从不更新条件的 while 循环。因此在编写 while 循环时应特别小心。

同上面所提到的,在 JavaScript 中还有 do...while 循环与 while 循环相似,不同处在于它总是至少运行一次,因为是在循环的末尾检查条件,而不是在开头。例如,上面的循环可以被改写为:

var x = 0;
do
{
    x = window.prompt("What is my favourite number?", x);
} while ((x != 42) && (x != null));

if (x == null)
    window.alert("You gave up!");
else
    window.alert("Yep - it's the Ultimate Answer!");

使用 break 和 continue 语句

在 Microsoft Jscript 中当某些条件得到满足时,用 break 语句来中断一个循环的运行。(请注意,也用 break 语句退出一个 switch 块。)。如果是一个 for 或者 for...in 循环,在更新计数器变量时使用 continue 语句越过余下的代码块而直接跳到下一个循环中。

下面的例子基于前面的示例用 break continue 语句控制循环。

var x = 0;
do
{
    x = window.prompt("What is my favourite number?", x);

    // 判断用户是否选择取消?如果是,退出循环。
    if (x == null)
        break;

    // 是否输入一个数?
    // 如果是则无需要求输入一个数。
    if (Number(x) == x)
        continue;

    //  要求用户只输入数字。
    window.alert("Please only enter in numbers!");

} while (x != 42)

if (x == null)
    window.alert("You gave up!");
else
    window.alert("Yep - it's the Ultimate Answer!");
JScript 函数

Microsoft Jscript 函数执行操作,也可以返回值。某些时候是计算或比较的结果。函数又被称为“全局方法”。


一个函数中包含有几个操作。这样可使得代码更合理化。可以写一组语句并给其命名,然后通过调用它并传递其需要的信息来运行整组语句。


给函数传递信息可以把信息放在函数名称后面的圆括号中。传递给函数的信息称作参数。某些函数根本不带任何参数,而其他函数带一个或者多个参数。在某些函数中,参数的个数取决于如何使用该函数。


Jscript 支持两种函数:一类是语言内部的函数,另一类是自己创建的。


特殊的内部函数


Jscript 语言包含很多内部函数。某些函数可以操作表达式和特殊字符,而其他函数将字符串转换为数值。一个有用的内部函数是 eval()。该函数可以对以字符串形式表示的任意有效的 Jscript代码求值。eval() 函数有一个参数,该参数就是想要求值的代码。下面给出一个使用本函数的示例。

eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
var x=10
document.write(eval(x+17))

创建自己的函数


在必要的时候,可以创建并使用自己的函数。一个函数的定义中包含了一个函数语句和一个 Jscript 语句块。


下面示例中的 Checktriplet 函数以三角形的边长为参数。通过查看三条边的长度是否可以组成一个毕达哥拉斯三元组(直角三角形斜边长度的平方等于其他两条边长的平方和)来计算该三角形是否为直角三角形。实际测试时 checkTriplet 函数要调用另两个函数中的一个函数。


注意在浮点数测试版本中极小数(“epsilon”)作为测试变量的使用。由于浮点运算的不确定性和舍入误差,除非问题中的三个值均已知为整数,直接测试这三个数是否组成毕达哥拉斯三元组是不可行的。因为直接的测试更为准确,本示例中的代码确定其是否可行,如果可行则使用它。


var epsilon = 0.00000000001; // 一些需要测试的极小数字。

// 测试整数的函数。
function integerCheck(a, b, c) 
{
   // 测试。
   if ( (a*a) == ((b*b) + (c*c)) )   
      return true;

   return false;
} // 整数检查函数的结尾。

// 测试浮点数的函数。
function floatCheck(a, b, c)   
{
   // 得到测试数值。
   var delta = ((a*a) - ((b*b) + (c*c)))

   // 测试需要绝对值
   delta = Math.abs(delta);

   // 如果差小于 epsilon,那么它相当接近。
   if (delta < epsilon)   
      return true;

   return false;
} // 浮点检查函数的末尾。


// 三元检查。
function checkTriplet(a, b, c)
{ 
   // 创建临时变量,用于交换值
   var d = 0; 

   // 先将最长的移动到位置“a”。

   // 需要的话交换 a  b
   if (b > a)
   {
      d = a;
      a = b;
      b = d;
   }

   // 需要的话交换 a  c
   if (c > a)
   {
      d = a;
      a = c;
      c = d;
   }

   // 测试全部的 3 个值,看其是否为整数?
   if (((a % 1) == 0) && ((b % 1) == 0) && ((c % 1) == 0))
   { 
      // 如果成立,使用精确检查。
      return integerCheck(a, b, c); 
   }
   else
   {
      // 如果不成立,取尽可能相近的。
      return floatCheck(a, b, c); 
   }
} // 三元检查函数的末尾。

// 下面的三个语句赋给范例值,用于测试。
var sideA = 5;
var sideB = 5;
var sideC = Math.sqrt(50.001);

// 调用函数。调用后,'result' 中包含了结果。
var result = checkTriplet(sideA, sideB, sideC);