在前面几章中,学习了 JavaScript 的核心 ECMAScript 以及该语言工作方式的基础知识。从本章开始,重点将转移到如何在 Web 浏览器中使用 JavaScript 。
自 Netscape Navigator 2.0 初次引入 JavaScript 以来, Web 浏览器已有了长足的发展。今天的浏览器不再只能处理传统的 HTML 文件,它们能处理各种格式的文件。具有讽刺意味的是,这些文件中的大多数都采用 JavaScript 作为动态改变客户端内容的方式。这一章探讨如何把 JavaScript 嵌入 HTML 及其他语言,并介绍了 BOM (浏览器对象模型)的一些基本概念。
5.1 HTML 中的 JavaScript
当然,第一个利用嵌入式 JavaScript 的语言还是 HTML ,因此首先讨论的自然是如何在 HTML 中使用 JavaScript 。 HTML 中嵌入 JavaScript 是从引入用于 JavaScript 的标签和为 HTML 的一些通用 部分增加了新特性开始的。
HTML 页面中包含 JavaScript 使用 <script/> 标签实现的。该标签通常放置在页面的 <head/> 标签中,最初定义的 <script/> 标签具有一个或两个特性, language 特性声明要使用的脚本语言, src 特性是可选的,声明要加入页面的外部 JavaScript 文件。 language 特性一般被设置为 JavaScript ,不过也可用它声明 JavaScript 的确切版本,如 JavaScript 1.3 (如果省略 language 特性,浏览器默认使用最新的 JavaScript 版本)。
尽管 <script/> 最初是为 JavaScript 设计的,但可以用于声明任意多种不同的客户端脚本语言, language 特性用于声明使用的代码的类型。例如,可把 language 特性设置为 VBScript ,使用 IE 的 VBScript 语言(只适用于 Windows )。
如果未声明 src 特性,在 <script/> 中即可以任意形式编写 JavaScript 代码。如声明了 src 特性,那么 <script/> 中的代码可能就是无效的(由浏览器决定)。例如:
这个例子中既有内嵌的 JavaScript 代码,又有对外部 JavaScript 文件的链接。使用 src 特性,即可像引用图像和样式表一样引用 JavaScript 文件。
虽然大多数浏览器并未要求,但根据规约,外部 JavaScript 文件的扩展名应为 .js (这样可以使用 JSP 、 PHP 或其他服务器端的脚本语言动态生成 JavaScript 代码)。
外部 JavaScript 语言的格式非常简单。事实上,它们只包含 JavaScript 代码的纯文本文件。在外部文件中不需要 <script/> 标签,引用文件的 <script/> 标签出现在 HTML 页中。这使得外部 JavaScript 文件看起来很像其他程序设计语言的源代码文件。
例如,考虑下面的内嵌代码:
要把函数 sayHi() 放在外部文件 external.js 中,需要复制函数文本自身(如图 5-1 所示)。
图 5-1
然后可更新 HTML 代码,加入这个外部文件:
对于 JavaScript 源文件中可加入哪些代码并无规定,这意味着可以给 JavaScript 文件加入任意多个类定义、函数,等等。
何时应该采用内嵌代码,何时采用外部文件呢?虽然关于这一点并无确定而且简洁的规则可循,不过一般认为,大量的 JavaScript 代码不应内嵌在 HTML 文件中,原因如下:
q 全性 ——只要查看页面的源代码,任何人都可确切地知道其中的代码做了什么。如果怀有恶意的开发者查看了源代码,就可能发现安全漏洞,危及整个站点或应用程序的安全。此外,在外部文件中还可加入版权和其他知识产权通告,而不打断页面流。
q 代码维护 ——如果 JavaScript 代码散布于多个页面,那么代码维护将变成一场恶梦。把所有 JavaScript 文件放在一个目录中要容易得多,这样在发生 JavaScript 错误时,就不会对放置代码的位置有任何疑问。
q 缓存 ——浏览器会根据特定的设置缓存所有外部链接的 JavaScript 文件,这意味着如果两个页面使用同一个文件,只需要下载该文件一次。这将加快下载速度。把同一段代码放在多个页面中,不止浪费,还增加了页面大小,从而增加下载时间。
一般说来,所有代码和函数的定义都在 HTML 页的 <head/> 标签中,这样在显示页面主体后,代码就被完全装载进浏览器,可供使用了。唯一该出现在 <body/> 标签中的是调用前面定义的函数的代码。
<script/> 放在 <body/> 内时,只要脚本所属的那部分页面被载入浏览器,脚本就会被执行。这样在载入整个页面之前,也可执行 JavaScript 代码。例如:
在这段代码中,方法 sayHi() 在页面显示所有文本前调用,这意味着警告消息将在文本 "This is the first text the user will see." 显示前弹出。建议不采用这种在页面的 <body/> 标签内调用 JavaScript 函数的方法,应该尽量避免它。相反的,建议在页面主体中只使用 事件处理函数 ( event handler ),例如:
这里,使用 <input/> 标签创建一个按钮,点击它时调用 sayHi() 方法。 onclick 特性声明一个事件处理函数,即响应特定事件的代码。第 9 章将详细讨论事件和事件处理函数。
注意,开始载入页面时, JavaScript 就开始运行了,因此有可能调用尚未存在的函数。在前面的例子中,把原来的 <script/> 标签放在函数调用后就会引发错误:
这个例子将引发错误,因为在定义 sayHi() 之前就调用了它。由于 JavaScript 是从上到下载入的,所以在遇到第二个 <script/> 标签前,函数 sayHi() 还不存在。注意这种问题,此外,如前所述,使用事件和事件处理函数调用 JavaScript 函数。
初次引入 JavaScript 时,只有一种浏览器支持它,因此大家开始关心,不支持 JavaScript 的浏览器如何处理 <script/> 标签及其中包含的代码。最后,设计了一种用于对旧的浏览器隐藏 JavaScri pt 代码(这是一个短语,在当今因特网上的许多 Web 站点的源代码中都能找到它)的格式。下面的代码在内嵌代码周围加入 HTML 注释,这样其他浏览器就不会在屏幕上显示这段代码。
第一行紧接起始标签 <script> 开始一条 HTML 注释。这样做是有效的,因为浏览器仍然把该行余下的部分看成 HTML 的一部分, JavaScript 代码从下一行开始。接下来的是常规的函数定义。第 2 行到最后一行是最有趣的部分,因为它以单行 JavaScript 注释标记(两个前斜线)开始,后面是 HTML 注释的结尾标记( --> )。这一行仍被看作 JavaScript 代码,所以单行注释标记是避免语法错所必需的。不过,旧的浏览器只承认 HMLT 注释的结束标记,因此,将忽略所有 JavaScript 代码。但是,支持 JavaScript 的浏览器只忽略该行,继续执行 </script> 标签。
尽管这种隐藏代码的方法在 Web 早期非常流行,今天却不再是必需的。目前,大多数 Web 浏览器都支持 JavaScript ,而不支持 JavaScript 的浏览器通常足够聪明,自己就能够忽略 JavaScript 代码。
不支持 JavaScript 的浏览器另外令人关注的是如何提供替代的内容。隐藏代码只是解决方法的一部分,开发者还需要一种方法,声明在 JavaScript 不能用时应该显示的内容。解决方法是采用 <noscript/> 标签,它可包含任何 HTML 代码(除 <script/> )。支持或启用 JavaScript 的浏览器会忽略这些 HTML 代码,不支持或者禁用 JavaScript 的浏览器则显示 <noscript/> 的内容。例如:
在这个例子中, <noscript/> 标签中有一条消息,告诉用户浏览器不支持 JavaScript 。第 8 章解释 <noscript/> 的实际用法。
近来,随着 XHTML (可扩展 HTML )标准的出现, <script/> 标签也经历了一些改变。该标签不再用 language 特性,而用 type 特性声明内嵌代码或要加入的外部文件的 mime 类型, JavaScript 的 mime 类型是 "text/javascript" 。例如:
即使许多浏览器不完全支持 XHTML ,但大多数开发者现在都用 type 特性,而不用 language 特性,以提供更好的 XHTML 支持。省略 language 特性不会带来任何问题,因为如前所述,所有浏览器都默认 <script/> 的该属性值为 JavaScript 。
XHTML 的第二个改变是使用 CDATA 段。 XML 中的 CDATA 段用于声明不应被解析为标签的文本( XHTML 也是如此),这样就可以使用特殊字符,如小于( < )、大于( > )、和号( & )和双引号( " ),而不必使用它们的字符实体。考虑下面的代码:
这个函数相当简单,它比较数字 a 和 b ,然后显示消息说明它们的关系。但是,在 XHTML 中,这段代码是无效的,因为它使用了三个特殊符号,即小于、大于和双引号。要修正这个问题,必须分别用这三个字符的 XML 实体 < 、 > 和 " 替换它们:
这段代码存在两个问题。首先,开发者不习惯用 XML 实体编写代码。这使代码很难读懂。其次,在 JavaScript 中,这种代码实际上将视为有语法错,因为解释程序不知道 XML 实体的意思。用 CDATA 段即可以以常规形式(即易读的语法)编写 JavaScript 代码。正式加入 CDATA 段的方法如下:
虽然这是正式方式,但还要记住,大多数浏览器都不完全支持 XHTML ,这就带来主要问题,即这在 JavaScript 中是个语法错误,因为大多数浏览器还不认识 CDATA 段。
当前使用的解决方案模仿了“对旧浏览器隐藏”代码的方法。使用单行的 JavaScript 注释,可在不影响代码语法的情况下嵌入 CDATA 段:
现在,这段代码在不支持 XHTML 的浏览器中也可运行。
与 type 特性一样,随着开发者为浏览器中的 XHTML 准备更好的支持, CDATA 的这种用法也越来越流行。但是,为避免 CDATA 的问题,最好还是用外部文件引入 JavaScript 代码。