1.1 Web脚本编程基础

阅读本书的读者很可能已经熟练使用万维网,而且对于使用某种HTML编写Web页面有一些基本的理解。

HTML(Hypertext Markup Language)不是编程语言(如其名所示),而是一款标签语言,用于标记页面的各个部分在浏览器里以何种方式展现,比如加粗或斜体字,或是作为标题,或是项目列表,或是数据表格,或是其他的标记方式。

一旦编写完成,这些页面的本质就决定了它们是静态的。它们不能对用户操作做出响应,不能进行判断,不能调整页面元素显示。无论用户何时访问这些页面,其中的标签都会以相同的方式进行解析和显示。

根据使用万维网的经验,我们知道网站可以做的事情很多。我们时常访问的页面基本上都不是静态的,它们能够包含“活”的数据,比如能够分享商品价格或航班到达时间,字体和颜色带有动画显示,或是具有单击浏览相册或排序数据列表这样的功能。

这些灵活的功能是通过程序(通常称为“脚本”)来实现的。脚本在后台运行,操控着浏览器显示的内容。

说明:脚本和程序

“脚本”这个术语显然来自话剧和电视领域,其中所用的脚本决定了演员或主持人要做的事情。对于Web页面来说,主角是页面上的元素,而脚本是由某种脚本语言(比如JavaScript)生成的。对于本书描述的内容来说,“程序”与“脚本”两个术语基本上是可以通用的。在本书中,两个术语都会用到。

1.1.1 服务器端与客户端编程

给静态页面添加脚本有如下两种最基本的方式。

➢ 让Web服务器在把页面发送给用户之前执行脚本。这样的脚本可以确定把哪些内容发送给浏览器以显示给用户,比如从在线商店的数据库获取产品价格,在用户登录到站点的私有区域之前核对用户身份,或是从邮箱获取邮件内容。这些脚本通常运行在Web服务器上,而且是在生成请求的页面并提供给用户之前运行的。因此,我们称之为服务器端脚本(server-side scripting)。

➢ 另一种方式并不是在服务器运行脚本,而是把脚本与页面内容一起发送给用户的浏览器。然后浏览器运行这些脚本,操作已经发送给浏览器的页面内容。这些脚本的主要功能包括动画页面的部分内容,重新安排页面布局,允许用户在页面内拖放元素,验证用户在表单里输入的内容,把用户重定向到其他页面,等等。我们自然而然地将这些脚本称为客户端脚本(client-side scripting)。

本书主要介绍JavaScript,它是互联网上应用最广泛的客户端脚本语言。

说明:JavaScript和Java

尽管JavaScript和Java的名字很相似,但是JavaScript和Java语言并没有多大关系,后者是由Sun Microsystems发明的。这两种语言的语法有相似之处,但是仅此而已,很多其他的编程语言也有和它们相似的语法。

1.1.2 JavaScript简介

用JavaScript编写的程序能够访问Web页面的元素以及运行该程序的浏览器,对这些元素执行操作,还可以创建新的元素。JavaScript常见的功能包括:

➢ 以指定尺寸、位置和样式(比如是否有边框、菜单、工具栏等)打开新窗口;

➢ 提供用户友好的导航帮助,比如下拉菜单;

➢ 检验Web表单输入的数据,在向Web服务器提交表单之前确保数据格式正确;

➢ 在特定事件(比如鼠标光标经过页面元素之上)发生时,改变页面元素的外观与行为;

➢ 检测和发现特定浏览器支持的高级功能,比如第三方插件,或是对新技术的原生支持。

由于JavaScript代码只在用户浏览器内部运行,页面会对JavaScript指令做出快速响应,从而增强了用户的体验,使得Web应用更像在用户的本地计算机运行的程序而不只是一个页面。另外,JavaScript能够检测和响应特定的用户操作(而HTML无法做到这一点),比如鼠标单击和键盘操作。

几乎所有Web浏览器都支持JavaScript。

1.1.3 JavaScript起源

JavaScript的历史可以追溯到20世纪90年代中期,首先是Netscape Navigator 2引入了1.0版本。

随后,欧洲计算机制造商协会(ECMA)开始介入,制定了ECMAScript规范,奠定了JavaScript迅猛发展的基础。与此同时,微软开发了自己版本的JavaScript—jScript,并将其用在IE浏览器上。

说明:JavaScript和VBScript

JavaScript不是仅有的客户端脚本语言,微软的浏览器还支持自己的Visual Basic面向脚本的版本—VBScript。但是,JavaScript得到了更好的浏览器支持—现代浏览器几乎都支持它。

1.1.4 浏览器的竞争

20世纪90年代后期,Netscape Navigator 4和IE 4都宣布对JavaScript提供更好的支持,比以前版本的浏览器大有改善。

但遗憾的是,这两组开发人员走上了不同的道路。他们分别给JavaScript语言本身及如何与Web页面交互定义了自己的规范。

这种荒唐的情况导致开发人员总是要编写两个版本的脚本,利用一些复杂的、经常可能导致错误的程序来判断用户在使用什么浏览器,然后再切换到适当版本的脚本。

好在网际网络联盟(W3C)非常努力地通过DOM来规范各个浏览器制作商生成和操作页面的方式。1级DOM于1998年完成,2级版本于2000年年末完成。

关于DOM是什么或它能做什么,本书的相应章节会有所介绍。

说明:关于W3C

网际网络联盟(World Wide Web Consortium,W3C)是一个国际组织,致力于制定开放标准来支撑互联网的长期发展。其官方网站包含了大量与Web标准相关的信息与工具。

1.1.5 <script>标签

当用户访问一个页面时,页面中包含的JavaScript代码会与其他页面内容一起传递给浏览器。

在HTML里使用<script>和</script>标签,可以在HTML代码里直接包含JavaScript语句。

<script>
    ...JavaScript statements...
</script>

说明:解释型语言和编译型语言

JavaScript是一种解释型语言,不是C++或Java那样的编译语言。JavaScript指令以纯文本形式传递给浏览器,然后依次解释执行。它们不必先“编译”成只有计算机处理器能够理解的机器码,这让JavaScript程序很便于阅读,能够迅速地进行编辑,然后在浏览器里重新加载页面就可以进行测试。

本书的代码都是符合HTML5规范的,也就是说,<script>元素没有任何必须设置的属性(在HTML5里,type属性是可选的,本书的范例里都没有使用这个属性)。但如果是在HTML4.x或XHTML页面里添加JavaScript,就需要使用type属性了:

<script type="text/javascript">
    ... JavaScript statements ...
</script>

偶尔还会看到<script>元素使用属性language="JavaScript",这种方式已经废弃很久了。除非是需要支持很古老的浏览器,比如Navigator或Mosaic,否则完全不必使用这种方式。

说明:关于废弃的代码

“废弃的”(deprecated)这个词对于软件功能或编码方式来说意味着尽量避免使用,因为它们被新功能或新方式取代了。

虽然为了实现向下兼容而仍然使用这类的功能,但“废弃的”这个状态通常意味着这样的功能会在不久之后被清除。

本书的范例把JavaScript代码放置到文档的body部分,但实际上JavaScript代码也能出现在其他位置。我们还可以利用<script>元素加载保存在外部文件中的JavaScript代码,关于这方面的详细介绍请见第2章。

1.1.6 DOM简介

“文档对象模型”(Document Object Model,DOM)是对文档及其内容的抽象表示。

每次浏览器要加载和显示页面时,都需要解释(更专业的术语是“解析”)构成页面的HTML源代码。在解析过程中,浏览器建立一个内部模型来表示文档里的内容,这个模型就是DOM。在浏览器渲染页面的可见内容时,就会引用这个模型。可以使用JavaScript来访问和编辑这个DOM的各个部分,从而改变页面的显示内容和用户交互的方式。

在早期,JavaScript只能对Web页面的某些部分进行最基本的访问,比如访问页面里的图像和表单。一个JavaScript程序所包含的语句,可以选择“页面上第二个表单”,或是“名称为registration的表单”。

Web开发人员有时把这种情形称为0级DOM,以便与W3C的1级DOM向下兼容。0级DOM有时也称为BOM(浏览器对象模型)。从0级DOM开始,W3C逐渐扩展和改善了DOM规范。W3C更大的野心是不仅让DOM能够用于Web页面与JavaScript,也能用于任何编程语言和XML。

说明:关于DOM级别

本书使用1级和2级的W3C DOM定义。

1.1.7 W3C和标准兼容

浏览器厂商在最近的版本中对DOM的支持都有了很大的改善。在编写本书时,IE最新版本是11,Netscape Navigator以Mozilla Firefox重生(当前版本是58.0),其他竞争对手还包括Opera、Konqueror、苹果公司的Safari、谷歌的Chrome和Chromium,它们都对DOM提供了出色的支持。

Web开发人员的处境有了很大改善。除了极特殊的一些情况,只要我们遵循DOM标准,基本上在编程时可以不考虑为某个浏览器编写特殊代码了。

说明:留意早期的浏览器

早期的浏览器,比如Netscape Navigator(任何版本)和IE 5.5以前的版本,现在基本上已经没有人使用了。本书只关注与1级或更高级别DOM兼容的现代浏览器,比如IE 9+、Firefox、Google Chrome、Apple Safari、Opera和Konqueror。我们建议读者把自己使用的浏览器升级到最新的较为稳定的版本。

1.1.8 window和document对象

浏览器每次加载和显示页面时,都在内存里创建页面及其全部元素的一个内部表示体系,也就是DOM。在DOM里,页面的元素具有一个逻辑化、层级化的结构,就像相互关联的父对象和子对象组成了一个树形的结构。这些对象及其相互关系构成了Web页面及显示页面的浏览器的抽象模型。每个对象都有“属性”列表来描述它,而利用JavaScript可以使用一些方法来操作这些属性。

这个层级树的最顶端是浏览器window对象,它是页面的DOM表示中一切对象的父对象。

window对象具有一些子对象,如图1.1所示。图1.1中第一个子对象是document,这也是本书最常使用的对象。浏览器加载的任何HTML页面都会创建一个document对象,包含全部HTML内容及其他构成页面显示的资源。利用JavaScript以父子对象的形式就可以访问这些信息。这些对象都具有自己的属性和方法。

图1.1 window对象及其一些子对象

图1.1中window对象的其他子对象还有location(包含着当前页面URL的详细信息)、history(包含浏览器以前访问的页面地址)和navigator(包含浏览器类型、版本和兼容的信息)。第4章将会更详细地介绍这些对象,其他章节也会使用它们,但目前我们着重于document对象。

1.1.9 对象表示法

我们用句点方式表示树形结构里的对象:

parent.child

如图1.1所示,location对象是window对象的子对象,所以在DOM里就像这样表示它:

window.location

提示:扩展点表示法

这种表示法可以扩展任意多次,以表示树结构中的任何对象。例如

object1.object2.object3

表示object3,其父对象是object2,而object2又是object1的子对象。

HTML页面的<body>部分在DOM里是document对象的一个子对象,所以表示为:

window.document.body

这种表示法的最后一个部分除了可以是对象外,还可以是属性或方法:

object1.object2.property
object1.object2.method

举例来说,如果想访问当前文档的title属性,也就是HTML标签<title>和</title>,我们可以这样表示:

window.document.title

注意:最好的还没来

如果对象层次和句点表示法似乎现在对你来说还不是很清晰,不必为此担心。在本书中,你将会看到很多的示例。

提示:一种方便的简写方式

window对象永远包含当前浏览器窗口,所以使用window.document就可以访问当前文档。作为一种简化表示,使用document也能访问当前文档。

如果是打开了多个窗口,或是使用框架集,那么每个窗口或框架都有单独的window和document对象,为了访问其中的某一个文档,需要使用相应的窗口名称和文档名称。

1.1.10 与用户交互

现在来介绍window和document对象的一些方法。首先介绍的这两个方法都能提供与用户交互的手段。

window.alert()

即使不知道window.alert(),我们实际上在很多场合已经看到过它了。window对象位于DOM层级的最顶端,代表了显示页面的浏览器窗口。当我们调用alert()方法时,浏览器会弹出一个对话框显示设置的信息,还有一个“确定”按钮。示例如下:

<script>window.alert("Here is my message");</script>

这是第一个使用句点表示法的范例,其中调用了window对象的alert()方法,所以按照object.method表示方法就写为window.alert。

提示:另一种方便的简写方式

在实际编码过程中,可以不明确书写window.这部分。因为它是DOM层级结构的最顶层(有时也被称为“全局对象”),任何没有明确指明对象的方法调用都会被指向window,所以

<script>alert("Here is my message");</script>

也能实现同样功能。

请注意要显示的文本位于引号之中。引号可以是双引号,也可以是单引号,但必须有引号,否则会产生错误。

这行代码在浏览器执行时,产生的弹出对话框如图1.2所示。

图1.2 一个window.alert()对话框

提示:不同的浏览器显示也不同

图1.2所示的弹出对话框由运行在Ubuntu Linux下的Chrome浏览器产生。不同操作系统、不同浏览器、不同显示设置都会影响这个对话框的最终显示情况,但它总是会包含要显示的信息和一个“OK”按钮。

提示:理解模态对话框

在用户单击“OK”按钮之前,页面上是不能进行其他任何操作的。具有这种行为模式的对话框称为“模态”对话框。

1.1.11 document.write()

从这个方法名称就可以猜到它的功能。显然它不是弹出对话框,而是直接向HTML文档写入字符,如图1.3所示。

<script>document.write("Here is another message");</script>

图1.3 使用document.write()

说明:

实际上,无论从功能来说,还是从编码风格与可维护性来说,document.write都是一种向页面输出内容的笨拙方式,它有很多的局限性。大多数正规的JavaScript程序员都不会使用这种方式,更好的方式是使用JavaScript和DOM。但在本书第一部分介绍JavaScript语言的基本知识时,我们还会使用这个方法。

实践


JavaScript编写的“Hello World!”

在介绍一种编程语言时,如果不使用传统的“Hello World!”范例似乎说不过去。这个简单的HTML文档如程序清单1.1所示。


程序清单1.1 一个alert()对话框中的“Hello World!”

<!DOCTYPE html>
<html>
<head>
    <title>Hello from JavaScript!</title>
</head>
<body>
    <script>
          alert("Hello World!");
    </script>
</body>
</html>

在文本编辑器里创建一个文档,将其命名为hello.html,输入上述代码,保存到计算机,然后在浏览器中打开它。

注意:留意文件名后缀

有些文本编辑器会尝试给我们指定的文件名添加.txt扩展名,因此在保存文件时要确保使用了.html扩展名,否则浏览器可能不会正常打开它。

几乎全部操作系统都允许我们用鼠标右键单击HTML文件图标,从弹出菜单里选择“打开方式”(或类似的字眼)。另一种打开方式是先运行喜欢的浏览器,然后从菜单栏里选择“文件”>“打开”,找到相应的文件,加载到浏览器。

这时会看到如图1.2所示的对话框,但其中的内容是“Hello World!”。如果计算机里安装了多个浏览器,可以尝试用它们都来打开这个文件,比较得到的结果。对话框外观可能有细微差别,但信息和“OK”按钮都是一样的。

注意:小心警告

有些浏览器的默认安全设置会在打开本地内容(比如本地计算机上的文件)时显示警告内容,如果看到这样的提示,只要选择允许继续操作即可。

1.1.12 读取document对象的属性

正如前文所述,DOM树包含着方法和属性。前面的范例展示了如何使用document对象的write方法向页面输出文本,现在我们来读取document对象的属性。以document.title属性为例,它包含了HTML页面的<title>标签中所定义的标题。

在文本编辑器里修改hello.html,修改对window.alert()方法的调用:

alert(document.title);

注意到document.title并没有包含在引号里,这时如果使用引号,JavaScript会认为我们要输出文本“document.title”。在不使用引号的情况下,JavaScript会把document.title属性的值传递给alert()方法,得到的结果如图1.4所示。

图1.4 显示document对象的属性