向 HTML 页面中插入 JavaScript 的主要方法,就是使用<script>元素。这个元素由 Netscape 创造并在 Netscape Navigator 2 中首先实现。后来,这个元素被加入到正式的 HTML 规范中。 HTML 4.01 为<script>定义了下列 6 个属性。

  • async:可选。表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本。只对外部脚本文件有效。
  • charset:可选。表示通过 src 属性指定的代码的字符集。由于大多数浏览器会忽略它的值,因此这个属性很少有人用。
  • defer:可选。表示脚本可以延迟到文档完全被解析和显示之后再执行。只对外部脚本文件有效。 IE7 及更早版本对嵌入脚本也支持这个属性。
  • language:已废弃。原来用于表示编写代码使用的脚本语言(如 JavaScript、JavaScript1.2或 VBScript)。大多数浏览器会忽略这个属性,因此也没有必要再用了。
  • src:可选。表示包含要执行代码的外部文件。
  • type:可选。可以看成是 language 的替代属性;表示编写代码使用的脚本语言的内容类型(也称为 MIME 类型)。虽然 text/javascript 和 text/ecmascript 都已经不被推荐使用,但人们一直以来使用的都还是 text/javascript。实际上,服务器在传送 JavaScript 文件时使用的MIME 类型通常是 application/x–javascript,但在 type 中设置这个值却可能导致脚本被忽略。另外,在非 IE浏览器中还可以使用以下值:application/javascriptapplication/ecmascript。考虑到约定俗成和最大限度的浏览器兼容性,目前 type 属性的值依旧还是text/javascript。不过,这个属性并不是必需的,如果没有指定这个属性,则其默认值仍为text/javascript。
  • 使用<script>元素的方式有两种:直接在页面中嵌入 JavaScript 代码和包含外部 JavaScript文件。

在使用<script>元素嵌入 JavaScript 代码时,只须为<script>指定 type 属性。然后,像下面这样把 JavaScript 代码直接放在元素内部即可:

<script type="text/javascript">
	function sayHi() {
		alert("Hi!");
	}
</script>

包含在<script>元素内部的 JavaScript 代码将被从上至下依次解释。就拿前面这个例子来说,解释器会解释一个函数的定义,然后将该定义保存在自己的环境当中。在解释器对<script>元素内部的所有代码求值完毕以前,页面中的其余内容都不会被浏览器加载或显示。在使用<script>嵌入 JavaScript 代码时,记住不要在代码中的任何地方出现"</script>"字符串。

例如,浏览器在加载下面所示的代码时就会产生一个错误:

<script type="text/javascript">
	function sayScript() {
		alert("</script>");
        }
</script>

因为按照解析嵌入式代码的规则,当浏览器遇到字符串"</script>"时,就会认为那是结束的</script>标签。而通过转义字符“/”可以解决这个问题,例如:

<script type="text/javascript">
	function sayScript() {
		alert("<\/script>");
	}
</script>

运行一下

这样写代码浏览器可以接受,因而也就不会导致错误了。

如果要通过<script>元素来包含外部 JavaScript 文件,那么 src 属性就是必需的。这个属性的值是一个指向外部 JavaScript 文件的链接,例如:

<script type="text/javascript" src="example.js"></script>

在这个例子中,外部文件 example.js 将被加载到当前页面中。外部文件只须包含通常要放在开始的<script>和结束的</script>之间的那些 JavaScript 代码即可。与解析嵌入式 JavaScript 代码一样,在解析外部 JavaScript 文件(包括下载该文件)时,页面的处理也会暂时停止。如果是在 XHTML 文档中,也可以省略前面示例代码中结束的</script>标签,例如:

<script type="text/javascript" src="example.js" />

但是,不能在 HTML 文档使用这种语法。原因是这种语法不符合 HTML 规范,而且也得不到某些浏览器(尤其是 IE)的正确解析。

按照惯例,外部 JavaScript 文件带有.js 扩展名。但这个扩展名不是必需的,因为浏览器不会检查包含 JavaScript 的文件的扩展名。这样一来,使用 JSP、 PHP 或其他服务器端语言动态生成 JavaScript 代码也就成为了可能。但是,服务器通常还是需要看扩展名决定为响应应用哪种 MIME 类型。如果不使用.js 扩展名,请确保服务器能返回正确的 MIME 类型。

需要注意的是,带有 src 属性的<script>元素不应该在其<script>和</script>标签之间再包含额外的 JavaScript 代码。如果包含了嵌入的代码,则只会下载并执行外部脚本文件,嵌入的代码会被忽略。

另外,通过<script>元素的 src 属性还可以包含来自外部域的 JavaScript 文件。这一点既让<script>元素倍显强大,又让它备受争议。在这一点上, <script>与<img>元素非常相似, 即它的 src属性可以是指向当前 HTML 页面所在域之外的某个域中的完整 URL,例如:

<script type="text/javascript" src="http://www.somewhere.com/afile.js"></script>

这样,位于外部域中的代码也会被加载和解析,就像这些代码位于加载它们的页面中一样。利用这一点就可以在必要时通过不同的域来提供 JavaScript 文件。不过,在访问自己不能控制的服务器上的JavaScript 文件时则要多加小心。如果不幸遇到了怀有恶意的程序员,那他们随时都可能替换该文件中的代码。因此,如果想包含来自不同域的代码,则要么你是那个域的所有者,要么那个域的所有者值得信赖。

无论如何包含代码,只要不存在 defer 和 async 属性,浏览器都会按照<script>元素在页面中出现的先后顺序对它们依次进行解析。换句话说,在第一个<script>元素包含的代码解析完成后,第二个<script>包含的代码才会被解析,然后才是第三个、第四个……

2.1.1 标签的位置

按照传统的做法,所有<script>元素都应该放在页面的<head>元素中,例如:

<!DOCTYPE html>
<html>
	<head>
		<title>
			Example HTML Page
		</title>
		<script type="text/javascript" src="example1.js"></script>
		<script type="text/javascript" src="example2.js"></script>
	</head>
	<body>
		<!-- 这里放内容 -->
	</body>
</html>

这种做法的目的就是把所有外部文件(包括 CSS 文件和 JavaScript 文件)的引用都放在相同的地方。可是,在文档的<head>元素中包含所有 JavaScript 文件,意味着必须等到全部 JavaScript 代码都被下载、解析和执行完成以后,才能开始呈现页面的内容(浏览器在遇到<body>标签时才开始呈现内容)。对于那些需要很多 JavaScript 代码的页面来说,这无疑会导致浏览器在呈现页面时出现明显的延迟,而延迟期间的浏览器窗口中将是一片空白。为了避免这个问题,现代 Web 应用程序一般都把全部 JavaScript 引用放在<body>元素中页面内容的后面,如下例所示:

<!DOCTYPE html>
<html>
	<head>
		<title>
			Example HTML Page
		</title>
	</head>
	<body>
		<!-- 这里放内容 -->
		<script type="text/javascript" src="example1.js"</script>
		<script type="text/javascript" src="example2.js"></script>
	</body>
</html>

这样,在解析包含的 JavaScript 代码之前,页面的内容将完全呈现在浏览器中。而用户也会因为浏览器窗口显示空白页面的时间缩短而感到打开页面的速度加快了。

2.1.2 延迟脚本

HTML 4.01 为<script>标签定义了 defer 属性。这个属性的用途是表明脚本在执行时不会影响页面的构造。也就是说,脚本会被延迟到整个页面都解析完毕后再运行。因此,在<script>元素中设置defer 属性,相当于告诉浏览器立即下载,但延迟执行。

<!DOCTYPE html>
<html>
	<head>
		<title>
			Example HTML Page
		</title>
		<script type="text/javascript" defer="defer" src="example1.js"></script>
		<script type="text/javascript" defer="defer" src="example2.js"></script>
	</head>
	<body>
		<!-- 这里放内容 -->
	</body>
</html>

在这个例子中,虽然我们把<script>元素放在了文档的<head>元素中,但其中包含的脚本将延迟到浏览器遇到</html>标签后再执行。 HTML5 规范要求脚本按照它们出现的先后顺序执行,因此第一个延迟脚本会先于第二个延迟脚本执行,而这两个脚本会先于 DOMContentLoaded 事件 (详见第 13 章)执行。在现实当中,延迟脚本并不一定会按照顺序执行,也不一定会在 DOMContentLoaded 事件触发前执行,因此最好只包含一个延迟脚本。

前面提到过, defer 属性只适用于外部脚本文件。这一点在 HTML5 中已经明确规定,因此支持HTML5 的实现会忽略给嵌入脚本设置的 defer 属性。 IE4~IE7 还支持对嵌入脚本的 defer 属性,但IE8 及之后版本则完全支持 HTML5 规定的行为。

IE4、 Firefox 3.5、 Safari 5 和 Chrome 是最早支持 defer 属性的浏览器。其他浏览器会忽略这个属性,像平常一样处理脚本。为此,把延迟脚本放在页面底部仍然是最佳选择。

在 XHTML 文档中,要把 defer 属性设置为 defer="defer"。

2.1.3 异步脚本

HTML5 为<script>元素定义了 async 属性。这个属性与 defer 属性类似,都用于改变处理脚本的行为。同样与 defer 类似, async 只适用于外部脚本文件,并告诉浏览器立即下载文件。但与 defer不同的是,标记为 async 的脚本并不保证按照指定它们的先后顺序执行。例如:

<!DOCTYPE html>
<html>
	<head>
		<title>
			Example HTML Page
		</title>
		<script type="text/javascript" async src="example1.js"></script>
		<script type="text/javascript" async src="example2.js"></script>
	</head>
	<body>
		<!-- 这里放内容 -->
	</body>
</html>

在以上代码中,第二个脚本文件可能会在第一个脚本文件之前执行。因此,确保两者之间互不依赖非常重要。指定 async 属性的目的是不让页面等待两个脚本下载和执行,从而异步加载页面其他内容。为此,建议异步脚本不要在加载期间修改 DOM。

异步脚本一定会在页面的 load 事件前执行,但可能会在 DOMContentLoaded 事件触发之前或之后执行。支持异步脚本的浏览器有 Firefox 3.6、 Safari 5 和 Chrome。

在 XHTML 文档中,要把 async 属性设置为 async="async"。

2.1.4 在XHTML中的用法①

可扩展超文本标记语言,即 XHTML(Extensible HyperText Markup Language),是将 HTML 作为XML 的应用而重新定义的一个标准。编写 XHTML 代码的规则要比编写 HTML 严格得多,而且直接影响能否在嵌入 JavaScript 代码时使用<script/>标签。以下面的代码块为例,虽然它们在 HTML 中是有效的,但在 XHTML 中则是无效的。

<script type="text/javascript">
	function compare(a, b) {
		if (a < b) {
			alert("A is less than B");
		} else if (a > b) {
			alert("A is greater than B");
		} else {
			alert("A is equal to B");
		}
	}
</script>

在 HTML 中,有特殊的规则用以确定<script>元素中的哪些内容可以被解析,但这些特殊的规则在 XHTML 中不适用。这里比较语句 a < b 中的小于号(<)在 XHTML 中将被当作开始一个新标签来解析。但是作为标签来讲,小于号后面不能跟空格,因此就会导致语法错误。

① HTML5 正快速地被前端开发人员采用,建议读者在学习和开发中遵循 HTML5 标准,本节内容可以跳过。

避免在 XHTML 中出现类似语法错误的方法有两个。一是用相应的 HTML 实体(&lt;)替换代码中所有的小于号(<),替换后的代码类似如下所示:

<script type="text/javascript">
	function compare(a, b) {
		if (a & lt; b) {
			alert("A is less than B");
		} else if (a > b) {
			alert("A is greater than B");
		} else {
			alert("A is equal to B");
		}
	}
</script>

虽然这样可以让代码在 XHTML 中正常运行,但却导致代码不好理解了。为此,我们可以考虑采用另一个方法。

保证让相同代码在 XHTML 中正常运行的第二个方法,就是用一个 CData 片段来包含 JavaScript 代码。在 XHTML(XML)中, CData 片段是文档中的一个特殊区域,这个区域中可以包含不需要解析的任意格式的文本内容。因此,在 CData 片段中就可以使用任意字符——小于号当然也没有问题,而且不会导致语法错误。引入 CData 片段后的 JavaScript 代码块如下所示:

<script type="text/javascript">
	< ![CDATA[function compare(a, b) {
		if (a < b) {
			alert("A is less than B");
		} else if (a > b) {
			alert("A is greater than B");
		} else {
			alert("A is equal to B");
		}
	}]] >
</script>

在兼容 XHTML 的浏览器中,这个方法可以解决问题。但实际上,还有不少浏览器不兼容 XHTML,因而不支持 CData 片段。怎么办呢?再使用 JavaScript 注释将 CData 标记注释掉就可以了:

<script type="text/javascript">
	//<![CDATA[
	function compare(a, b) {
		if (a < b) {
			alert("A is less than B");
		} else if (a > b) {
			alert("A is greater than B");
		} else {
			alert("A is equal to B");
		}
	}
	//]]>
</script>

这种格式在所有现代浏览器中都可以正常使用。虽然有几分 hack 的味道,但它能通过 XHTML 验证,而且对 XHTML 之前的浏览器也会平稳退化。

在将页面的 MIME 类型指定为"application/xhtml+xml"的情况下会触发XHTML 模式。并不是所有浏览器都支持以这种方式提供 XHTML 文档。

2.1.5 不推荐使用的语法

在最早引入<script>元素的时候,该元素与传统 HTML 的解析规则是有冲突的。由于要对这个元素应用特殊的解析规则,因此在那些不支持 JavaScript 的浏览器(最典型的是 Mosaic)中就会导致问题。具体来说,不支持 JavaScript 的浏览器会把<script>元素的内容直接输出到页面中,因而会破坏页面的布局和外观。

Netscape 与 Mosaic 协商并提出了一个解决方案,让不支持<script>元素的浏览器能够隐藏嵌入的JavaScript 代码。这个方案就是把 JavaScript 代码包含在一个 HTML 注释中,像下面这样:

<script>
	< !--
	function sayHi() {
		alert("Hi!");
	}
	//-->
</script>

给脚本加上 HTML 注释后, Mosaic 等浏览器就会忽略<script>标签中的内容;而那些支持JavaScript 的浏览器在遇到这种情况时,则必须进一步确认其中是否包含需要解析的 JavaScript 代码。

虽然这种注释 JavaScript 代码的格式得到了所有浏览器的认可,也能被正确解释,但由于所有浏览器都已经支持 JavaScript,因此也就没有必要再使用这种格式了。在 XHTML 模式下,因为脚本包含在XML 注释中,所以脚本会被忽略。

2.1 <script>元素【JavaScript高级程序设计第三版】的更多相关文章

  1. JavaScript高级程序设计第三版.CHM【带实例】

    从驱动全球商业.贸易及管理领域不计其数的复杂应用程序的角度来看,说 JavaScript 已经成为当今世界上最流行的编程语言一点儿都不为过. JavaScript 是一种非常松散的面向对象语言,也是 ...

  2. DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  3. 10.2 DOM 操作技术【JavaScript高级程序设计第三版】

    很多时候,DOM 操作都比较简明,因此用JavaScript 生成那些通常原本是用HTML 代码生成的内容并不麻烦.不过,也有一些时候,操作DOM 并不像表面上看起来那么简单.由于浏览器中充斥着隐藏的 ...

  4. 12.2.1 访问元素的样式【JavaScript高级程序设计第三版】

    任何支持style 特性的HTML 元素在JavaScript 中都有一个对应的style 属性.这个style 对象是CSSStyleDeclaration 的实例,包含着通过HTML 的style ...

  5. 14.5 富文本编辑【JavaScript高级程序设计第三版】

    富文本编辑,又称为WYSIWYG(What You See Is What You Get,所见即所得).在网页中编辑富文本内容,是人们对Web 应用程序最大的期待之一.虽然也没有规范,但在IE 最早 ...

  6. 10.1.2 Document类型【JavaScript高级程序设计第三版】

    JavaScript 通过Document 类型表示文档.在浏览器中,document 对象是HTMLDocument(继承自Document 类型)的一个实例,表示整个HTML 页面.而且,docu ...

  7. 22.1 高级函数【JavaScript高级程序设计第三版】

    函数是JavaScript 中最有趣的部分之一.它们本质上是十分简单和过程化的,但也可以是非常复杂和动态的.一些额外的功能可以通过使用闭包来实现.此外,由于所有的函数都是对象,所以使用函数指针非常简单 ...

  8. JavaScript高级程序设计第三版-读书笔记(1-3章)

    这是我第一次用markdown,也是我第一次在网上记录我自己的学习过程. 第一章 JavaScript主要由以下三个不同的部分构成 ECMAScript   提供核心语言功能 DOM     提供访问 ...

  9. 模拟事件【JavaScript高级程序设计第三版】

    事件,就是网页中某个特别值得关注的瞬间.事件经常由用户操作或通过其他浏览器功能来触发.但很少有人知道,也可以使用JavaScript 在任意时刻来触发特定的事件,而此时的事件就如同浏览器创建的事件一样 ...

随机推荐

  1. css3实现3D立体翻转效果

    1.在IE下无法显示翻转效果,火狐和谷歌可以 /*样式css*/ .nav-menu li { display: inline; } .nav-menu li a { color: #fff; dis ...

  2. SDL第一个程序:加载一张图片

    直接看代码吧 using System; using System.Collections.Generic; using System.ComponentModel; using System.Dat ...

  3. 安装 vue.js和第一个hello world

    一.在自己的项目文件中使用npm下载vue npm install vue 二.在文件中引入vue.js 三.第一个hello world 注:scritpt代码必须写在html代码的下面

  4. Android Bitmap实战技巧

    注:本文大量参考谷歌官方文档自http://developer.android.com/intl/zh-cn/training/displaying-bitmaps/index.html.如果你自学能 ...

  5. [Effective C++ --013]以对象管理资源

    这一节基本讲述的是将资源放进管理对象,防止忘记释放资源. 1.一般New和Delete使用场景 void fun() { SimpleClass* pSimpleClass1 = new Simple ...

  6. LoadRunner性能测试-loadrunner事务

    事务(Transaction): 简单来说就是用来模拟用户的一个相对完整的业务过程.添加事务,是用来衡量响应时间的重要方法.我们可以通过事务计时来对不同压力负载下的性能指标进行对比. 插入事务的方法: ...

  7. require和require_once的区别

    require 的使用方法如 require("./inc.php"); .通常放在 PHP 程式的最前面,PHP 程式在执行前,就会先读入 require 所指定引入的档案,使它 ...

  8. 网络通信 --&gt; epoll用法

    epoll用法 在linux的网络编程中,很长的时间都在使用select来做事件触发.在linux新的内核中,有了一种替换它的机制,就是epoll. epoll函数 1. 创建epoll的句柄 siz ...

  9. Handler使用小结

    个人概念里面handler用来更新UI.一直有一个问题困恼我,为什么我在主线程里面创建一个Handler不需要传递传递Looper,而在一个子线程里面必须调用Looper.prepare, Loope ...

  10. https与http的区别

    HTTPS协议 由于http协议中,服务器和客户端之间传输的报文是明文,很容易被攻击截取,为了保证一些敏感信息的安全,https协议在http的基础上加了一层SSL协议,依靠证书来保证服务器和客户端之 ...