首页 > > > javascript面向对象编程.pdf

javascript面向对象编程.pdf

javascript面向对象编程.pdf

上传者: weidong1365381 2011-09-14 评分1 评论0 下载1152 收藏10 阅读量1182 暂无简介 简介 举报

简介:本文档为《javascript面向对象编程pdf》,可适用于IT书籍领域,主题内容包含第一部分:现代JavaScript简介第一章现代JavaScript编程JavaScript的演化是渐进而稳固的。历经过去十年的进程JavaScri符等。

1 第一部分:现代 JavaScript简介 第一章 现代 JavaScript编程 JavaScript 的演化是渐进而稳固的。历经过去十年的进程,JavaScript 在人们的认知里 已经从一门简单的玩物式的语言逐渐发展成为一门倍受推崇的编程语言,被全世界的公司和 开发者用来构造种种精彩的应用。现代 JavaScript编程语言一如既往地可靠、健壮,强大得 令人难以置信。在本书中我进行的许多论述,将揭示是什么使得现代 JavaScript应用程序与 从前有着那么明显的不同。本章中出现的许多概念远不能算新奇,然而成千上万聪明的程序 员的认同促使它们的用途得以升华并最终形成今天的格局。既如此,我们这就来着眼现代 JavaScript程序设计。 面向对象的 JavaScript 从语言的视角来看,面向对象的程序设计和面向对象的 JavaScript语言绝对不是什么摩登的 东西;JavaScript最开始就是被设计成一种彻底的面向对象语言。然而,随着 JavaScript在 其使用和接受的过程中的“逐步发展”,其它语言(如 Ruby,Python,和 Perl等)的程序员留意到 了它并开始将他们的编程模式引入了 JavaScript。 面向对象的 JavaScript代码的外观和内部运作都有别于其它具有对象能力的语言。在第 二章我将深入论述使它如此独特的方方面面,而在这里,先来看一点基础的东西以体会编写 现代 JavaScript代码的初步感觉。程序 1-1中的两个对象构造器的例子,演示了可用于学校 课程的简单的对象搭配。 程序 1-1. 课程和课程表的面向对象 JavaScript表述 CODE: //类 Lecture的构造器 //使用两个字符串参数,name和 teacher function Lecture( name, teacher ) { //把它们作为对象的本地属性保存 this.name = name; this.teacher = teacher; } //类 Lecture的方法,生成一个显示该课程信息的字符串 Lecture.prototype.display = function(){ return this.teacher + " is teaching " + this.name; }; //类 Schedule的构造器 //使用一个 lectures类型的数组作为参数 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 2 function Schedule( lectures ) { this.lectures = lectures; } //类 Schedule的方法,用来构造一个描述该课程表的字符串 Schedule.prototype.display = function(){ var str = ""; //遍历每门课程,累加构成信息字符串 for ( var i = 0; i < this.lectures.length; i++ ) str += this.lectures[i].display() + " "; return str; }; 从程序 1-1的代码中你或许已经看出,大部分的面向对象基本原则贯穿存在于其中,但 它们是以不同于其它更常见的面向对象语言的方式组织起来的。你可以创建对象构造器和方 法,并存取对象属性。程序 1-2展示了在应用程序中使用上面两个类的一个示例。 程序 1-2. 给用户提供课程的列表 CODE: //创建一个新的课表对象,存于变量 mySchedule中 var mySchedule = new Schedule([ //创建一个课程对象的数组, //作为传给课表(原文此处为 Lecture,疑为笔误)对象的唯一参数 new Lecture( "Gym", "Mr. Smith" ), new Lecture( "Math", "Mrs. Jones" ), new Lecture( "English", "TBD" ) ]); // 弹出对话框显示课表的信息 alert( mySchedule.display() ); 伴随对广大程序员对 JavaScript 的接受,设计良好的面向对象代码的使用也正日益普 及。贯穿本书的始末,我将试图展示我认为能够最好地例示代码设计与实现的不同的面向对 象的 JavaScript代码片段。 测试你的代码 建立起良好的面向对象的基本代码之后,开发专业品质的 JavaScript代码的第二个方面 是确保拥有一个强劲的代码测试环境。当开发频繁使用的或将由其它开发者维护的代码时, 严格调试的必要性会显得尤为突出。为其它开发者提供一个坚实的测试基础,是维持代码开 发活动的关键。 在第四章,你将会看到一些可用来形成良好的测试/使用框架的不同工具,以及对复杂 应用程序的简单调试。用于 Firefox的插件 Firebug就是其中一例。Firebug提供了许多的有 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 3 用的工具,如错误控制台,HTTP 请求日志,调试,以及元素查看。图 1-1 展示了 Firebug 调试一段代码时的实况截屏。 图 1-1. Firefox Firebug插件运行时的截屏 开发干净的、可测试的代码的重要性怎么强调都不会过分。一旦你开始开发一些干净的 面向对象代码并将它们与合适的测试套件结合,相信你会倾向于同意这一点。 为分发而进行的封装 开发现代的专业 JavaScript代码的最后一个方面是为了代码分发或在现实世界里中使 用而进行的封装处理。随着开始开发者们在其页面中使用越来越多的 JavaScript代码,冲突 的可能性将会增加。如果两个 JavaScript库里都有一个名为 data的变量或者按各的意图添 加事件,灾难性的冲突和莫名其妙的错误可能就会出现。 开发者简单地置入<script>指针无须任何变动就能正常工作的能力是开发一个成功的 JavaScript库的精诣所在。开发者用以保持代码清洁和普遍兼容的的技术或解决方案有许多 种。 使用命名空间是广泛使用的保证代码不与其它 JavaScript代码互相影响和抵触的一种 技术。这方面一个极端的(但未必是最好或最有用的)运作中的例子就是 Yahoo开发的任 何人都可使用的用户界面库。使用该库的一个示例见程序 1-3. 程序 1-3. 使用重度名称空间化的 YahooUI库给一个元素添加事件 CODE: //给 ID为"body"的元素添加 mouseover事件监听器 YAHOO.util.Event.addListener('body','mouseover',function(){ //and change the background color of the element to red this.style.backgroundColor = 'red'; }); 然而,这种命名空间方法存在一个问题,即库与库之间在构造和使用的方式上缺乏内在 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 4 的一致性。正是在这一点上,中心代码仓库如 JSAN(JavaScript Archive Network)变得非常 有用。JSAN 提供一套代码库需遵从的一致规则,以及一种快捷导入代码所依赖的其它库的 方式。图 1-2展示了 JSAN的主分发中心的一个截屏。 图 1-2. 公共代码仓库 JSAN的截屏 我将在第三章阐述开发清洁的可封装代码的细节。此外,其它常见的事故多发点如事件 处理冲突,将在第六章论述。 Unobtrusive DOM脚本编程(非侵入的 DOM脚本编程) 基于一个优良的可测试的核心创建你的代码和兼容的分发,是 Unobtrusive DOM脚本 编程的基本概念。编写 unobtrusive代码意味着与你的 HTML内容的彻底分离:数据来自服 务器,而 JavaScript代码用来使其动态化。达到这一彻底分离的最重要的副作用就是你的代 码在不同的浏览器之间可以完美的升/降级。利用这一点,你可以提供高级的内容给支持它 的浏览器,而在不支持的浏览器上从容隐藏之。 编写现代的、Unobtrusive代码包括两个方面:文档对象模型(DOM)和 JavaScript事件。 本书中我对这两个方面都将作深入的解释。 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 5 文档对象模型 DOM是表示 XML文档的流行的方法。它未必是最快的、最轻便的、或者最易使用 的,却是是最普及的,绝大多数 web开发语言(如 Java,Perl,PHP,Ruby,Python,及 Javascript)都实现了对它的支持。DOM旨在为开发者提供一种直观的方式来导航于 XML的 层次结构中。 因为有效的 HTML只是 XML的一个子集,保有一个方式来有效地解析和浏览 DOM文档 对于简化 JavaScript开发来说是必不可少的。从根本上讲,出现在 JavaScript中的大多数的 交互是发生在 JavaScript与页面所包含的不同 HTML元素之间的;DOM是使这此过程简单 化的卓越工具。程序 1-4展示了使用 DOM在页内导航和查找不同的元素然后操作它们的一 些例子。 程序 1-4. 使用文档对象模型定位并操纵不同的 DOM元素 [Copy to clipboard] [ - ] CODE: <html> <head> <title>Introduction to the DOM</title> <script> //直到文档完全载入,我们才能操作 DOM window.onload = function() { //找到文档中所有的<li>元素 var li = document.getElementsByTagName("li"); //然后给它们全部加上边框 for ( var j = 0; j< li.length; j++ ) { li[j].style.border = "1px solid #000"; } //定位 ID为'everywhere'的元素 var every = document.getElementById( "everywhere" ); //并将它从文档中移除 every.parentNode.removeChild( every ); }; </script> </head> <body> <h1>Introduction to the DOM</h1> <p class="test">There are a number of reasons why the DOM is awesome, here are some:</p> <ul> <li id="everywhere">It can be found everywhere.</li> <li class="test">It's easy to use.</li> <li class="test">It can help you to find what you want, PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 6 really quickly.</li> </ul> </body> </html> DOM是开发 Unobtrusive JavaScript代码的第一步。借助简单快速导航 HTML文档的 能力,所有随之而来的 JavaScript/HTML交互将变得如此简单。 事件 事件将一个应用程序之内所有的用户交互结合在一起。在一个设计良好的 JavaScript应用程 序里,你将拥有数据源和它的视觉的表示(在 HTML DOM内部)。为了同步这两个方面,你 必须监视用户的交互动作并试图相应地更新用户界面。使用 DOM和 JavaScript事件的结合 是使得现代 web应用程序赖以工作的基本组合。 所有的现代浏览器都提供一系列的只要特定交互动作发生即被触发的事件,如用户移动 鼠标,敲击键盘,或离开页面等等。使用这些事件,你可以注册代码到特定事件,一旦该事 件发生,你的代码就会被执行。程序 1-5展示了这种交互的一个实例,该网页中的<li>元素 在用户鼠标经过的时候会改变背景色。 程序 1-5. 使用 DOM和事件来提供一些视觉效果 [Copy to clipboard] [ - ] CODE: <html> <head> <title>Introduction to the DOM</title> <script> //直到文档完全载入,我们才能操作 DOM window.onload = function(){ //查找所有的<li>元素,附以事件处理程序 var li = document.getElementsByTagName("li"); for ( var i = 0; i < li.length; i++ ) { //将鼠标移入事件处理程序附在<li>元素上, //该程序改变<li>背景颜色为蓝色 li[i].onmouseover = function() { this.style.backgroundColor = 'blue'; }; //将鼠标移出事件处理程序附在<li>元素上, //该程序将<li>的背景颜色改回白色 li[i].onmouseout = function() { this.style.backgroundColor = 'white'; }; } PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 7 }; </script> </head> <body> <h1>Introduction to the DOM</h1> <p class="test">There are a number of reasons why the DOM is awesome, here are some:</p> <ul> <li id="everywhere">It can be found everywhere.</li> <li class="test">It's easy to use.</li> <li class="test">It can help you to find what you want, really quickly.</li> </ul> </body> </html> JavaScript事件是复杂多样的。本书中的大多数代码或应用程序都以某种方式利用了事 件。第六章和附属B完全专注于事件及其交互。 JavaScript与 CSS 动态 HTML建立在 DOM和事件交互的基础上。在核心层面上,动态 HTML表示发 生在 JavaScript和附着在 DOM元素上的 CSS信息的交互。 层叠式样式表(CSS)作为布局的标准服务于简单的不唐突的网页,在最小化了用户端兼 容性问题的同时,提供给开发者以强大的可控制性。从根本上讲,动态 HTML 就是探索 JavaScript和CSS彼此交互作用时能够达到什么以及怎样最好地利用该联合达成令人印象深 刻的效果。 更高级的交互示例如拖放元素和动画效果见第七章。在那里我将围绕它们展开深入论 述。 Ajax Ajax,或曰异步 Javascript与 XML,是由 Adaptive Path公司的创办人之一兼董事长 Jesse James Garrett 在 其 论 文 "Ajax:Web 应 用 程 序 的 新 途 径 "(http://www.adaptivepath.com/publ ... archives/000385.php)中创造的一个术语。它描述了请求和提交额外的信息 时发生于客户和服务器之间的高级交互。 术语 Ajax 包括了许多种数据据通讯的可能组合,但它们都围绕一个中心前提:附加的 数据请求是在页面完全载入之后由客户端向服务器发起的。这允许应用程序开发者超越缓慢 的、传统的应用程序流程,创建与用户相关的额外交互。图 1-3是来自 Garrett的 Ajax论文 的一个图示,说明了应用程序中由于额外的请求发生在后台(而且用户很可能并不知情),交 互的流程发生了怎样的改变。 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 8 图 1-3:来自文章"Ajax:Web应用程序的新途径"的图示,展示发生于客户和服务器之间 的先进的异步的交互 Garrett 论文的最初发表,激起了用户、开发者、设计者以及管理者们的兴趣,使用高 级交互的新型应用程序爆炸式地增长。讽刺的是,在这一兴趣复苏的同时,Ajax 背后的技 术却是相当陈旧的(在 2000 年左右就有已有了商业上的应用)。然而最主要的不同在于,老 的应用程序利用了浏览器特有的方式与服务器通讯(如仅 ie具有的功能)。由于所有的现代 浏览器都支持 XMLHttpRequest(发送或从服务器接收数据的主要手段),the playing field has been leveled(见#12 cfs178的回复),每个人都可以享受其益处。 如果说有一个公司走在了利用 Ajax技术创建优秀应用程序的最前列,那无疑是 Google。 恰在最初的 Ajax论文出现之前,它发布了一个高交互性的 domo:Google Suggest。该 demo 可以实时地自动完成你所键入的查询,这是旧式的页面重载不可能达到的功能。图 1-4 是 Google Suggest运行时的一个截屏。 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 9 图 1-4. Google Suggest,早于 Garrett的 Ajax论文的利用了异步 XML技术的应用程序 除此而外,Google的另一个革命性的应用程序为 Google Map,用户在其地图上移动将 会实时地看到相关的局部结果。这一程序通过使用 Ajax 技术而提供的速度和可用性的水平 是其它任何可用的地图程序所无法比拟的,结果彻底地变革了在线地图市场。图 1-5 是 Google Map的截屏. 图 1-5. Google Maps,利用了一些 Ajax技术来动态载入特定区域信息 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 10 浏览器支持 JavaScript开发所面临的不幸事实是,因为与实现和支持它的浏览器关联过于紧密,它 受到当前最流行浏览器的支配。由于用户未必会使用对 JavaScript支持得最好的浏览器,我 们被迫对哪些是最重要的功能作出抉择。 许多开发者已经开始做的是去掉对那些导致过多开发障碍的浏览器的支持。因为它们用 户群的规模和还是因为它们拥有你喜欢的功能而考虑对浏览器的支持,需要仔细的权衡。 最近 Yahoo发布了一个可用来扩展你的 web应用程序的 JavaScript库。连同那个库, 它还发布了一些供 web 开发者遵从的指导方针。以我之见,从中产生的最重要的文档是 Yahoo支持与不支持的各种浏览器的官方的列表。尽管任何人或任何公司都可以做类似的事 情,一份由互联上访问最频繁的网站所提供的文档,其价值绝对无法估量。 Yahoo开发了一个分级的浏览器支持策略,对浏览器指定特定的级别并依据其功能为它 提供不同的内容。Yahoo给浏览器三个级别:A,X和 C: A级浏览器是得到完全支持和测试的,Yahoo的所有程序都能有保障在其中运行。 X 级浏览器是 Yahoo 认可但是没能彻底测试的准 A 级浏览器,或者是崭新的从未遇到 过的浏览器。X级浏览器被期望能处理高级的内容,与A级浏览器等同对待。 C级浏览器是已知的“劣质的”浏览器,不支持运行 Yahoo应用程序所必须的功能。由于 Yahoo 应用程序完全 Unobtrusive(即使没有 JavaScript 它们也能继续工作),这些浏览器只 需处理不含 JavaScript的功能性的内容。 顺便一提,Yahoo的浏览器级别选择竟与我的不谋而合,这使得它尤其富有吸引力。在 这本书里,我大量地使用了术语“现代浏览器”,当我用这一措词的时候,我指的 Yahoo浏览 器分级表评定为 A 级的任浏览器。给定一组赖以工作的一致的功能,减少因避免浏览器的 不兼容而带来的痛苦,学习和开发的经历将会变得更加有趣。 我 极 力 推 荐 你 们 去 通 读 浏 览 器 分 级 的 支 持 文 档 ( 见 http://developer.yahoo.com/yui/articles/gbs/gbs. html,该文档包含了图 1-6所示的浏览器支持表),感受一下 Yahoo力图实现的是什么。 通过将些信息公之于 web开发的大众,Yahoo正在给出一条无价的“黄金标准”让其它所有人 去靠拢,这是很了不起的。 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 11 图 1-6. Yahoo提供的浏览器分组支持表 更多的关于浏览器支持情况的信息请参看本书的附录 C,那里对每种浏览器的缺点和长 处都有深入的论讨。或多或少地,你会发现所有的 A 级浏览器都走在发展的最前列,提供 了远远超出你的开发所需要的功能。 当选择你希望支持哪些浏览器时,最终结果实际上可以归结为你的应用程序支持的一组 功能。如果你想要支持 NS4或 IE5(举个例子来说),则势必严格地限制你可以在程序中使 用的功能的数量,因为它们缺乏对现代编程技术的支持。 尽管如此,了解哪些浏览器是现代的允许你利用其中可用的强大的功能并给你一个可供 将来的开发所依据的稳固的基础。这一稳固的开发基础可由以下几种功能所定义: 核心 Javascript 1.5: 最近、最广泛接受的 JavaScript 版本。它全面支持面向对象的 JavaScript。IE5.0不支持全部的 1.5,这是开发者们不愿意支持它的主要原因。 XML文档对象模型(DOM)2:用来访问 HTML和 XML文档的的标准方案。这绝对是编写高 效率的程序不可或缺的。 XMLHttpRequest: Ajax技术的支柱——用来发起 HTTP请求的一个简单层。所有的浏览器 默认都支持这一对象,除了 IE5.0-6.0;而它们也都支持用 ActiveX初始化功能相当的对象。 CSS: 网页设计的基本需求。这似乎像是一个额外的需求,但是拥有 CSS对 web应用程 序开发者来说是必不可少的。由于每一种现代浏览器都支持 CSS,大多数问题的发生通常归 结为呈现方面的差异。这正是 IE for Mac较少被频繁支持的主要原因。 以上这些浏览器功能的结合构成了开发 JavaScript web应用程序的支柱。所有的现代浏 览器都以某种方式支持以上列举的功能。本书论述的所有内容都基于这一假设:你所使用的 浏览器最起码能支持它们 本章摘要 本书试图完全包括所有现代、专业的 JavaScript编程技术,以期它们被从独立开发 者到大型公司的每一个人使用,使得其代码更加可用、可读、具有交互性。 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 12 在这一章里我们对这本书里将会出现的每一个知识点做了一个简短的总览。这包括专业 JavaScript 编程的基础:编写面象对代码,测试代码,为分发而进行封装。随后你看到了 Unobtrusive DOM脚本编程的主要方面,包括一个关于文档对象模型,事件,JavaScript与 CSS交互的简短的总览。最后你看到了 Ajax背后的前提和在现代浏览器中 JavaScript 的支 持。这些话题加在一起,足够带你步入专业级 JavaScript程序员的行列。 第二部分 专业的 JavaScript开发 第二章 面对对象的 JavaScript 对象是 JavaScript的基本单位。实际上 JavaScript中一切都是对象并得益于这一事实。然而, 为了增强这一纯粹的面向对象的语言,JavaScript包括了一个庞大的功能集,使它无论是在 潜在能力还是风格上,都成为一门极其独特的语言。 本章中我将开始覆盖 JavaScript语言的最重要的一些方面,如引用,作用域,闭包,以 及上下文,你会发现这正是其它 JavaScript书籍中很少论及的。打下主要的基础以后,我们 将开始探索面向对象 JavaScript的几个重点,包括对象到底如何运作和怎样创建新的对象并 在特定的许可条件下设置其方法。如果你认真去读的话,这很可能是本书中最重要的一章, 它将彻底地改变你看待 JavaScript作为一门编程语言的方式。 语言特性 引用 JavaScript的一个重要的方面是引用的概念。引用就是指向对象实际位置的指针。 这是一项极其强大的功能。前提是,实际的对象决不是一个引用:字符串总是一个字符串, 数组总是一个数组。然而,多个变量可以引用相同的对象。JavaScript就是以这种引用引用 机制为基础。通过维护一系列的指向其它对象的引用,语言为你提供了更大的弹性。 另外,对象能包括一系列的属性,这些属性简单地引用其它对象(如字符串,数字,数 组等等)。当几个变量指向相同对象时,修改底层对象类型将会在所有的指点向它的变量上 有所反映。例 2-1即此一例,两个变量指向同一个对象,但是对对象内容的修改的反映是全 局的。 程序 2-1. 多变量引用单个对象的示例 [Copy to clipboard] [ - ] CODE: //设置 obj为一个空对象 var obj = new Object(); //objRef现在引用了别的对象 var objRef = obj; //修改原始对象的属性 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 13 obj.oneProperty = true; //我们可以发现该变化在两个变量中都可以看到 //(因为他们引用了同一个对象) alert( obj.oneProperty === objRef.oneProperty ); 我从前提到过自更改的对象在 JavaScript里非常少见的。让我们看一个发生这一状况的 实例。数组对象能够用 push方法给它自己增加额外的项。因为在数组对象的核心,值是作 为对象的属性存储的,结果类似程序 2-1中的情形,一个对象成为全局被改动的(导致了多 个变量的值被同时改变)。见程序 2-2. 程序 2-2. 自修改对象的例子 [Copy to clipboard] [ - ] CODE: //创建一组项目的数组 var items = new Array( "one", "two", "three" ); //创建一个对项目数组的引用 var itemsRef = items; //给原始数组添加一项 items.push( "four" ); //两个数组的长度应该相同, //因为它们都指向相同的数组对象 alert( items.length == itemsRef.length ); 记住这一点是很重要的:引用总是只指向最终被引用的对象,而不会是引用本身。例如, 在 Perl语言里,很可能有一个引用指向另一个也是引用的变量。但在 JavaScript里,它会 沿着引用链向下追溯直到指向核心的对象。程序 2-3演示了这种情形,物理的目标已经改变 而引用仍然指向原来的对象。 程序 2-3. Changing the Reference of an Object While Maintaining Integrity(见#9 oerrite 的回复) [Copy to clipboard] [ - ] CODE: // 设置 items为一个字符串的数组(对象) var items = new Array( "one", "two", "three" ); // 设置 itemsRef为对 items的引用 var itemsRef = items; //让 items指向一个新的对象 items = new Array( "new", "array" ); // items和 itemsRef现在指向不同的对象 // items指向 new Array( "new", "array" ) // itemsRef则指向 new Array( "one", "two", "three" ) alert( items !== itemsRef ); PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 14 最后,让我们来看一个陌生的例子,表面似乎是一个自修改的对象,却作用于一个新的 未被引用的对象。当执行字符串串联时,结果总是一个新的字符串对象,而非原字符串更改 后的版本。这在程序 2-4中可以看出。 程序 2-4. 对象修改作用于一个新的对象而非自修改对象的示例 [Copy to clipboard] [ - ] CODE: //让 item等于一个新的字符串对象 var item = "test"; //itemRef也引用相同的字符串对象 var itemRef = item; //在字符串对象上串联一个新的对象 //注意:这创建了一个新的对象,并不修改初始对象 item += "ing"; //item和 itemRef的值并不相等,因为 //一个全新的对象被创建了 alert( item != itemRef ); 如果你刚刚接触,引用可能是个令人头大的刁钻话题。然而,理解引用是如何工作的对 于编写良好、干净的 JavaScript代码是极其重要的。接下来的几节我们将探究几种未必新鲜 和令人激动的,但是同样对编写良好、干净的代码很重要的特性。 函数重载和类型检查 其它面向对象的语言(比如 Java)的一种共有的特性是“重载”函数的能力:传给它们 不同数目或类型的参数,函数将执行不同操作。虽然这种能力在 JavaScript中不是直接可用 的,一些工具的提供使得这种探求完全成为可能。 在 JavaScript的每一个函数里存在一个上下文相关的名为 arguments的变量,它的行 为类似于一个伪数组,包含了传给函数的所有参数。参数不是一真正的数组(意味着你不能 修改它,或者调用 push()方法增加新的项),但是你可以以数组的形式访问它,而且它也的 确有一个 length属性。程序 2-5中有两个示例。 程序 2-5. JavaScript中函数重载的两个示例 [Copy to clipboard] [ - ] CODE: //一个简单的用来发送消息的函数 function sendMessage( msg, obj ) { //如果同时提供了一个消息和一个对象 if ( arguments.length == 2 ) //就将消息发给该对象 obj.handleMsg( msg ); PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 15 //否则,刚假定只有消息被提供 else //于是显示该消息 alert( msg ); } //调用函数,带一个参数 – 用警告框显示消息 sendMessage( "Hello, World!" ); //或者,我们也可以传入我们自己的对象用 //一种不同方式来显示信息 sendMessage( "How are you?", { handleMsg: function( msg ) { alert( "This is a custom message: " + msg ); } }); //一个使用任意数目参数创建一个数组的函数 function makeArray() { //临时数组 var arr = []; //遍历提交的每一个参数 for ( var i = 0; i < arguments.length; i++ ) { arr.push( arguments[i] ); } //返回结果数组 return arr; } 另外,存在另一种断定传递给一个函数的参数数目的方法。这种特殊的方法多用了一点 点技巧:我们利用了传递过来的任何参数值不可能为 undefined这一事实。程序 2-6展示一 了个简单的函数用来显示一条错误消息,如果没有传给它,则提供一条缺省消息。 程序 2-6: 显示错误消息和缺省消息 [Copy to clipboard] [ - ] CODE: function displayError( msg ) { //检查确保 msg不是 undefined if ( typeof msg == 'undefined' ) { //如果是,则设置缺省消息 msg = "An error occurred."; } //显示消息 alert( msg ); } PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 16 typeof语句的使用引入了类型检查。因为 JavaScript(目前)是一种动态类型语言,使 得这个话题格外有用而重要的话题。有许多种方法检查变量的类型;我们将探究两种特别有 用的。 第一种检查对象类型的方式是使用显式的 typeof操作符。这种有用的方法给我们一个 字符串名称,代表变量内容的类型。这将是一种完美的方案,除非变量的类型或者数组或自 定义的对象如 user(这时它总返回"ojbect",导致各种对象难以区分)。 这种方法的示例见程序 2-7 程序 2-7. 使用 typeof决定对象类型的示例 [Copy to clipboard] [ - ] CODE: //检查我们的数字是否其实是一个字符串 if ( typeof num == "string" ) //如果是,则将它解析成数字 num = parseInt( num ); //检查我们的数组是否其实是一个字符串 if ( typeof arr == "string" ) //如果是,则用逗号分割该字符串,构造出一个数组 arr = arr.split(","); 检查对象类型的第二种方式是参考所有 JavaScript对象所共有的一个称为 constructor 的属性。该属性是对一个最初用来构造此对象的函数的引用。该方法的示例见程序 2-8。 程序 2-8. 使用 constructor属性决定对象类型的示例 [Copy to clipboard] [ - ] CODE: //检查我们的数字是否其实是一个字符串 if ( num.constructor == String ) //如果是,则将它解析成数字 num = parseInt( num ); //检查我们的字符串是否其实是一个数组 if ( str.constructor == Array ) //如果是,则用逗号连接该数组,得到一个字符串 str = str.join(','); 表 2-1显示了对不同类型对象分别使用我所介绍的两种方法进行类型检查的结果。表格 的第一列显示了我们试图找到其类型的对象。每二列是运行 typeof Variable(Variable为第一 列所示的值)。此列中的所有结果都是字符串。最后,第三列显示了对第一列包含的对象运 行 Variable.constructor所得的结果。些列中的所有结果都是对象。 表 2-1. 变量类型检查 ——————————————————————————————— Variable typeof Variable Variable.constructor PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 17 ——————————————————————————————— {an:"object"} object Object ["an","array"] object Array function(){} function Function "a string" string String 55 number Number true boolean Boolean new User() object User —————————————————————————————————— 使用表 2-1的信息你现在可以创建一个通用的函数用来在函数内进行类型检查。可能到 现在已经明显,使用一个变量的 constructor作为对象类型的引用可能是最简单的类型检查 方式。当你想要确定精确吻合的参数数目的类型传进了你的函数时,严格的类型检查在这种 可能会大有帮助。在程序 2-9中我们可以看到实际中的一例。 程序 2-9. 一个可用来严格维护全部传入函数的参数的函数 [Copy to clipboard] [ - ] CODE: //依据参数列表来严格地检查一个变量列表的类型 function strict( types, args ) { //确保参数的数目和类型核匹配 if ( types.length != args.length ) { //如果长度不匹配,则抛出异常 throw "Invalid number of arguments. Expected " + types.length + ", received " + args.length + " instead."; } //遍历每一个参数,检查基类型 for ( var i = 0; i < args.length; i++ ) { //如 JavaScript某一项类型不匹配,则抛出异常 if ( args[i].constructor != types[i] ) { throw "Invalid argument type. Expected " + types[i].name +", received " + args[i].constructor.name + " instead."; } } } //用来打印出用户列表的一个简单函数 function userList( prefix, num, users ) { //确保 prefix是一个字符串,num是一个数字, //且 user是一个数组 strict( [ String, Number, Array ], arguments ); //循环处理 num个用户 for ( var i = 0; i < num; i++ ) { PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 18 //显示一个用户的信息 print( prefix + ": " + users[i] ); 变量类型检查和参数长度校验本身是很简单的概念,但是可用来实现复杂的方法,给开 发者和你的代码的使用者提供更好的体验。接下来,我们将探讨 JavaScript中的作用域以及 怎么更好的控制它。 作用域 作用域是 JavaScript中一个较难处理的特性。所有面向对象的编程语言都有某种形式的 作用域;这要看是什么上下文约束着作用域。在 JavaScript里,作用域由函数约束,而不由 块约束(如 while,if,和 for里的语句体)。最终可能使得一些代码的运行结果表面上显得怪异 (如果你来自一种块作用域语言的话)。程序 2-10的例子说明了“函数作用域代码”的含义。 代码 2-10. JavaScript中变量作用域是怎样工作的例子 [Copy to clipboard] [ - ] CODE: //设置一个等于"test"的全局变量 foo var foo = "test"; //在 if块中 if ( true ) { //设置 foo为"new test" //注意:这仍然是在全局作用域中 var foo = "new test"; } //正如我们在此处可见,foo现在等于"new test" alert( foo == "new test" ); //创建一个修改变量 foo的函数 function test() { var foo = "old test"; } //调用时,foo却驻留在是在函数的作用域里面 test(); //确认一下,foo的值仍然是"new test" alert( foo == "new test" ); 在程序 2-10中你会发现,变量位于在全局作用域。基于浏览器的 JavaScript有趣的一 面是,所有的全局变量实际上都是 window对象的属性。尽管一些老版本的 Opera浏览器或 Safari浏览器不是这样,假定浏览器这样工作通常是一个很好的经验规则。程序 2-11展示 了一个这种例子。 程序2-11. JavaScript的全局变量 与 window对象的例子 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 19 [Copy to clipboard] [ - ] CODE: //全局变量,包含字符串"test" var test = "test"; //你会发现,我们的全局变量和 window的 test属性是相同的 alert( window.test == test ); 最后,让我们来看看当一个变量漏定义时会怎样。程序 2-12里,变量 foo在 test()的作 用域里被赋值。但是,程序 2-12里实际并没有(用 var foo)定义变量的作用域。当变量 foo 没有明确定义时,它将成为全局变量,即使它只在函数的上下文使用。 程序 2-12. 隐式全局变量声明的示例 [Copy to clipboard] [ - ] CODE: //一个为变量 foo赋值的函数 function test() { foo = "test"; } //调用函数为 foo赋值 test(); //我们发现 foo现在是全局变量了 alert( window.foo == "test" ); 到目前应该很明显,尽管 JavaScript的作用域不如块作用域语言的严格,它还是相当强 大和有特色的。尤其是与下节中叙述的闭包的概念结合起来时,JavaScript语言的强大将展 露无遗。 闭包 闭包意味着内层的函数可以引用存在于包绕它的函数的变量,即使外层的函数的执行已 经终止。这一特殊的论题可能是非常强大又非常复杂的。我强烈推荐你们参考本节后面将提 及的站点,因为它有一些关于闭包这一话题的精彩的信息。 我们先来看程序 2-13所示的闭包的两个简单例子。 程序 2-13. 闭包改善的代码清晰性的两例 [Copy to clipboard] [ - ] CODE: //得到 id为"main"的元素 var obj = document.getElementById("main"); //改变它的边框样式 obj.style.border = "1px solid red"; //初始化一个 1秒钟以后被调用的回调函 数 PDF 文件使用 "pdfFactory Pro" 试用版本创建 www.fineprint.cn 20 setTimeout(function(){ //此函数将隐藏该元

该用户的其他资料

  • 名称/格式
  • 评分
  • 下载次数
  • 资料大小
  • 上传时间

用户评论

0/200
    暂无评论
上传我的资料

相关资料

资料评价:

/ 150
所需积分:1 立即下载
返回
顶部
举报
资料
关闭

温馨提示

感谢您对爱问共享资料的支持,精彩活动将尽快为您呈现,敬请期待!