JavaScript忍者秘籍

978-7-115-40194-6
作者: 【美】John Resig(莱西格) Bear Bibeault(贝比奥特)
译者: 徐涛
编辑: 陈冀康

图书目录:

详情

本书分设计、构建和维护3个阶段介绍全新的JavaScript开发技术。首先让读者建立牢固的基本知识,然后讲解如何构建JavaScript库,解释了构建JavaScript库需要应付和解决的问题的解决方案和开发策略,还介绍了保证代码运行良好的维护技术。

图书摘要

版权信息

书名:JavaScript忍者秘籍

ISBN:978-7-115-40194-6

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] John Resig Bear Bibeault

  译    徐 涛

  责任编辑 陈冀康

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


John Resig是可汗学院计算机科学学院的院长,也是jQuery JavaScript库的创造者。排名前10000的网站中,目前有57%的网站使用jQuery(BuiltWith.com统计),并且有几百万其他网站也使用jQuery,它已成为最受欢迎的用于构建网站的技术,可能也是一直以来最流行的编程技术之一。

他还创建了许多其他开源工具和项目,包括Processing.js(Processing语言到JavaScript的转换)、QUnit(测试JavaScript代码的测试套件)和TestSwarm(用于分布式JavaScript测试的平台)。

他目前正在可汗学院进一步开展计算机科学教育,他在学校开发计算机科学课程和工具,来教各个年龄层的人如何编程。可汗学院的目标是创造优秀的免费教育资源。他不仅教人们如何编程,还让每一位程序员体验写完自己的第一个程序后的兴奋。

目前,John住在纽约布鲁克林,业余时间喜欢研究Ukiyo-e(日本版画)。

Bear Bibeault编写软件已经超过30年,一开始是通过一个100波特的电传打字机在控制数据网络超级计算机上编写井字程序。因为Bear有两个电气工程学位,因此应该是从事设计天线之类的工作,但从他在数字设备公司从事的第一份工作开始,他总是更着迷于编程。

Bear还分别在Lightbridge Inc.、BMC Software、Dragon Systems、Works.com等其他几个公司工作过。Bear甚至曾在美国军队服役,教步兵学习如何炸毁坦克,这些技能在每日例会上还能派上用场。

Bear目前担任一家家庭网关设备和电视机顶盒领域领先供应商的软件架构师。

Bear是其他一些Manning图书的作者:jQuery in Action(第一版和第二版)、Ajax in PracticePrototype and Scriptaculous in Action,他还是O’Reilly出版的许多网络Head First图书的技术复审员,如Head First AjaxHead Rush AjaxHead First Servlets and JSP

除了日常工作外,Bear还写书(duh!),并经营着一家小型企业,致力于创建Web应用程序,提供其他媒体服务(但不是婚礼摄像——永远不会是婚礼摄像),并作为“引领者”(非常资深的版主)帮着打理CodeRanch.com。

不在电脑前待着时,Bear喜欢做大餐、涉足摄影和视频,也喜欢驾驶雅马哈V-Star和穿热带印花衬衫。

他工作和居住在得克萨斯州奥斯汀,他深爱这座城市,除了满城的疯狂司机外。


我们不能总是向软件发起正面攻击。有时候要从侧面或后面偷袭。我们需要掌握工具的“军火库”并了解每一个绝密技巧。这就要求我们必须要成为一名忍者。

本书带领读者走上JavaScript启蒙之路。它从关键概念开始讲起,比如函数、对象和闭包之间的关系,从大师的角度来一一解析。本书为你提供对日常所使用技术的新见解,并探索了不为人知的特性和功能,帮助读者从学徒成长为忍者。阅读完本书以后,你就可以开始编写更加出彩的JavaScript应用程序了,甚至也可以编写自己的代码库和框架。

本书包括以下内容:

“本书出自两位忍者之手,介绍了编写有效跨浏览器JavaScript的艺术。”

——Glenn Stokol,Oracle公司

“本书符合jQuery的座右铭,‘更少代码,更多功能’。”

——Andre Roberge,圣安妮大学

“本书介绍了有趣且原创的技术。”

——Scott Sauyet,Four Winds Software

“读完这本书,你就不会再盲目地插入代码片段,并惊叹于它是如何工作的了——你会明白它的工作原理。”

——Joe Litton,JoeLitton.net协作软件开发者

“本书将助你把JavaScript水平提升到大师级别。”

——Christopher Haupt,Greenstack.com

本书卖点

本书内容极具深度,技术含量高,作者是jQuery JavaScript库的创造者,在JS领域享有盛誉。

JavaScript语言非常重要,相关的技术图书也很多,但没有任何一本书对JavaScript语言的最重要部分(函数、闭包和原型)进行深入、全面的介绍,也没有任何一本书讲述跨浏览器代码的编写。本书是jQuery库创始人编写的一本深入剖析JavaScript语言的书。


Original English language edition, entitled Secrets of the JavaScript Ninja by John Resig and Bear Bibeault published by Manning Publications Co., 209 Bruce Park Avenue, Greenwich, CT 06830. Copyright ©2013 by Manning Publications Co.

Simplified Chinese-language edition copyright ©2015 by Posts & Telecom Press. All rights reserved.

本书中文简体字版由Manning Publications Co.授权人民邮电出版社独家出版。未经出版者书面许可,不得以任何方式复制或抄袭本书内容。

版权所有,侵权必究。


JavaScript语言非常重要,相关的技术图书也很多,但没有任何一本书对JavaScript语言的最重要部分(函数、闭包和原型)进行深入、全面的介绍,也没有任何一本书讲述跨浏览器代码的编写。本书是jQuery库创始人编写的一本深入剖析JavaScript语言的书。

本书共分4个部分,从准入训练、见习训练、忍者训练和火影训练四个层次讲述了逐步成为JavaScript高手的全过程。全书从高级Web应用程序开发者所面临的挑战谈起,由浅入深地覆盖了测试和测试工具、函数、闭包、对象、正则表达式、定时器、运行时代码求值、with语句、跨浏览器问题、元素的特性和属性、事件处理、DOM以及CSS选择器等众多核心话题;将严谨的理论讲解和实用的代码示例相结合,引导读者更加深入地了解JavaScript的神奇,充分展示了JavaScript语言的各种特性。

本书适合具备一定JavaScript基础知识的读者阅读,也适合从事程序设计工作并想要深入探索JavaScript语言的读者阅读。


参与编写本书的人数会让大多数人感到意外。这一大本书(或在屏幕上阅读的电子书)的完成结合了许多编著者的共同努力。

Manning的员工与我们共同努力,确保本书达到我们所期望的质量水平,我们非常感谢他们的付出。没有他们本书就不可能完成。本书的“结尾致谢”不仅包括我们的出版商Marjan Bace、编辑Mike Stephens,还包括以下编著者:Jeff Bleiel、Douglas Pudnick、Sebastian Stirling、Andrea Kaucher、Karen Tegtmayer、Katie Tennant、Megan Yockey、Dottie Marsico、Mary Piergies、Andy Carroll、Melody Dolab、Tiffany Taylor、Dennis Dalinnik、Gabriel Dobrescu和Ron Tomich。

要非常地感谢审稿专家,他们帮助我们为本书定稿,从寻找简单的错别字到纠正术语和代码中的错误,再到组织书中的章节。他们每个人都审查了整本书,极大地提高了本书的质量。非常感谢他们花时间审阅本书:Alessandro Gallo、André Roberge、Austin King、Austin Ziegler、Chad Davis、Charles E. Logston、Chris Gray、Christopher Haupt、Craig Lancaster、Curtis Miller、Daniel Bretoi、David Vedder、Erik Arvidsson、Glenn Stokol、Greg Donald、James Hatheway、Jared Hirsch、Jim Roos、Joe Litton、Johannes Link、John Paulson、Joshua Heyer、Julio Guijarro、Kurt Jung、Loïc Simon、Neil Mix、Robert Hanson、Scott Sauyet、Stuart Caborn和Tony Niemann。特别要感谢Valentin Crettaz,他担任本书的技术编辑。除了检查多个环境中示例代码的每个例子,还对文本的技术准确性提出了宝贵的意见,找到了最初遗漏的信息,并及时更新了浏览器中的JavaScript和HTML5支持。

还要特别感谢Bert Bates,他为改进本书提供了宝贵的反馈意见。花在Skype上的大量时间也得到了回报。

我要感谢我的父母多年来的支持和鼓励。他们为我提供了很多资源和工具,激发了我对编程的兴趣——他们一直都在鼓励我。

关于我出版的第五本书,我想要感谢的人有很多,包括javaranch.com的成员和员工。不加入JavaRanch,我就不会有机会开始写作,所以我衷心感谢Paul Wheaton和Kathy Sierra让我开始了这项工作,以及其他给予我鼓励和支持的工作人员,包括(但不限于)Eric Pascarello、Ernest Friedman Hill、Andrew Monkhouse、Jeanne Boyarsky、Bert Bates和Max Habibi。

同样要感谢和我住在一起的伙伴Jay、宠物狗Little Bear和Cozmo,它们在家里忍受寂寞,而我始终埋头写书。除了向它们抱怨一下Word、某个浏览器或者任何引起我愤怒的事情外,我很少从键盘上抬起头。

最后,我要感谢我的合著者John Resig。没有他,本书就不会存在。


在拿到这本书的英文稿时,我如获至宝,不到一个礼拜便全部阅读了一遍,因为这才是我心目中的“圣经”。

虽然在市面上,几乎每个礼拜都有JavaScript相关的新书上市,而且几乎每一本都有不同的侧重点,或是实战练习,或是框架讲解,但却没有一本书籍对JavaScript的核心部分进行深入的讲解。

2012年的时候,我曾经零零散散整理了大约50篇关于JavaScript核心内容的文章,并发布到了博客园网站,这些文章虽然都有提及这些核心内容,但却没有很强的系统性。直到阅读完本书,我发现这才是我心目中的“圣经”,它不是规范的照搬,也不是示例的讲解,也不是jQuery的源码分析,而是作者结合开发jQuery时的经验以及其他专家多年来经验的总结。

本书没有对JavaScript的基本类型、操作符、对象等基本概念进行讲解,在介绍完基本的测试和调试知识后,就开始讲解JavaScript语言的最重要部分:函数、闭包以及原型。本书用了整整两章对函数进行讲解,从普通函数、匿名函数、递归函数以及函数表达式等的声明,到函数的调用,每个细节都深入地进行了讲解,同时穿插讲解了函数的缓存、重载、存储等方面的知识。在讲解闭包的时候,深入讲解了作用域和作用域链,通过对函数上下文的理解,我们又看到了偏应用函数、即时函数、函数包装等一系列与闭包相关的各种技巧和原理解释。而在原型讲解的时候,不仅讲解了基于原型和原型链的各种继承方式,同时也讲解了基于类(Class)风格的面向对象编程实现方式。

正则表达式、线程和定时器,这三项内容,不管在哪种语言学习中,都是最难以理解的部分。作者花了整整两章内容对其进行讲解,足以显示出对这些内容的重视,同时,作者在开发jQuery库的时候也是大量利用了这三项技术内容。

接下来的内容,是我在其他书上从来没有见过的,分别是代码求值、with语句、跨浏览器策略、HTML元素的Attribute、Property、Class等相关内容的深入讲解,这些内容是开发jQuery的基石,没有对这些内容的深入理解,作者也根本无法开发出这么受欢迎的jQuery库来。

最重要的部分通常都是放在最后,事件、DOM操作、CSS选择器引擎,这三部分虽然不属于JavaScript语言规范本身的部分,但却是前端开发中最重要的部分了,不深入理解这三部分,基本上做不出太好的前端程序。在事件方面,除了讲解了不同浏览器的冒泡和委托机制,作者还讲述了自己在jQuery库中是如何实现事件模块的,通过事件中枢管理系统提供一个高效的事件管理中心,从而对各种浏览器的各种事件做出实时的响应。在DOM操作章节,作者并没有提及jQuery中的attr、html、text、addClass等快捷方式的使用,而且通过各种基本知识,讲解如何实现复杂的DOM操作。在CSS选择器引擎方面,作者讲解了4种不同的选择器实现方式,通过逐一讲解,让我们了解到了每一种实现方式的优缺点,以及使用时的注意事项。

本书教授的是核心原理,而不是其他书中常见的用法示例。理解了原理,自然就可以一通百通,其他剩余的只不过是各种各样的技巧罢了。读完本书,再回过头来看看其他的JavaScript书籍,你的阅读体验自然就会完全不同了。

徐涛

2015年9月


2008年年初,在我开始编写本书时,我发现了一个真正的需求:没有任何一本书对JavaScript语言的最重要部分(函数、闭包和原型)进行深入、全面的介绍,也没有任何一本书讲述跨浏览器代码的编写。可惜的是,到目前为止情况并没有改善,真令人惊讶。

人们把越来越多的精力投入到了开发新技术上,例如源于HTML5的新技术或ECMAScript的新版本。但如果不能很好地理解JavaScript语言的基本特性,就无法深入地钻研新技术,或者使用最热门的库。虽然浏览器开发的未来是光明的,但事实上,大多数的开发都需要确保代码适用于大多数浏览器和大部分的潜在用户。

虽然本书酝酿了很长一段时间,但幸好还没过时。我的合著者Bear Bibeault对本书进行了很好的修正,他确保了本书的内容在很长一段时间内都很实用。

花这么长时间编写本书的主要原因是,我在不断地积累经验,为编写后面章节的跨浏览器代码做准备。我对跨浏览器开发的大部分了解是来自于jQuery JavaScript库的实践。在编写后面跨浏览器开发章节时,我意识到jQuery的大部分核心内容都可以用不同的方式编写、优化,从而用于更广泛的浏览器。

或许在编写完本书以后,jQuery的最大改变是从使用浏览器特征判断转化为功能特性判断。这可以让jQuery进行无限制使用,而无需假设浏览器总是有特定的bug或遗失某些特性。

这些变化的结果是,jQuery预料到浏览器在过去几年经历的许多改进:谷歌发布了Chrome浏览器;由于移动计算越来越流行,用户代理的数量激增;Mozilla、谷歌和苹果已经进入了浏览器性能之争;微软终于开始对Internet Explorer进行实质性的改进。不能再假定浏览器渲染引擎(如WebKit或Internet Explorer中的Trident)总是按同一种方式做事。技术在发生着快速的变化,也被越来越多的用户所使用。

使用本书所讲述的技术,jQuery的跨浏览器功能能够保证,用jQuery编写的代码将能够在各种浏览器环境中运行。这使得jQuery在过去4年中高速增长,根据BuiltWith.com的记录,在排名前10000家的网站中,现在有超过57%的网站使用jQuery。

JavaScript的一些相对不变的功能,例如代码求值、有争议的with语句和计时器,其使用方式仍然很有趣。现在有许多很积极的编程语言基于JavaScript或者可以编译成JavaScript,如CoffeeScript和Processing.js等。这些语言需要复杂的语言解析、代码求值和作用域操作,以实现有效运行。虽然动态代码求值因其复杂性和潜在的安全问题而一直遭到诋毁,但如果没有它,我们就不会有CoffeeScript这门编程语言,该语言影响了即将到来的ECMAScript规范本身。

我个人正在使用所有这些功能,即使是现在在可汗学院工作的时候也是一样。浏览器中的动态代码求值是一个非常强大的功能:可以构建浏览器内编程环境,做一些疯狂的事情,例如将代码注入到实时运行环境中。这种功能将为学习计算机编程带来一个非常吸引人的方式,它所提供的新功能是传统的学习环境所无法提供的。

浏览器开发的未来仍然非常光明,这主要是因为很多功能都被封装在JavaScript和浏览器API中了。准确掌握JavaScript语言的最重要部分,并且积极编写能够在很多浏览器中都能运行的代码,有助于创建优雅、快速、普适的代码。


JavaScript非常重要。这并不总是如此,但现在确实如此。

Web应用程序将为用户提供丰富的用户界面体验,没有JavaScript,我们也就只能显示几张小图片。Web开发人员比以往任何时候都更需要熟练掌握能够为Web应用程序带来生命的语言。

像橙汁和早餐一样,JavaScript不再只用于浏览器了。该语言推倒了浏览器的界限,可用在Rhino和V8等引擎的服务器上,也可以用于像node.js这样的框架。

虽然本书主要是介绍用于Web应用程序的JavaScript,但本书第二部分提出的JavaScript基础适用范围也很广泛。

随着使用JavaScript的开发人员在逐渐增多,熟练掌握JavaScript基础比以往任何时候都更加重要,这样他们就可以成为真正的语言忍者。

这本书不能作为你的第一本JavaScript图书。如果你是JavaScript完全新手,或者只是通过搜索网络获得代码片段了解了一些语句,那么本书还不适合你阅读。

本书面向至少掌握JavaScript基础的Web开发人员。你应该理解JavaScript语句的基本结构以及创建简单页面脚本的工作原理。你不需要是该语言的高级用户——这是本书的目标,但你不应是一位新手。

你还应该有HTML和CSS方面的工作经验。再次强调,不需要了解特别高级的知识,但你应该知道拼凑Web网页的基础知识。

如果你想获得一些好的必备资料,寻找一本关于JavaScript和Web开发方面的流行图书,然后解决这个问题。我们推荐的JavaScript图书:David Flanagan的《JavaScript权威指南》、Douglas Crockford的《JavaScript语言精粹》以及Michael Morrison的Head First JavaScript

本书旨在通过四个部分让你从学徒升级为忍者。

第一部分介绍了我们往下要学习的主题和所需要的一些工具。

第二部分主要关注JavaScript基础:该语言中你习以为常但不太清楚其工作原理的部分。这可能是本书中最重要的部分,即使你只阅读了该部分,也会对JavaScript语言有更深入的理解。

在第三部分,我们利用在第二部分中学到的基础知识解决浏览器留给我们的棘手问题。

第四部分总结本书内容,主要讨论从创建jQuery等高级JavaScript库中学到的东西。

让我们看一下每一章的简要内容。

第1章介绍我们作为高级Web应用程序作者所面临的挑战。提出浏览器扩散引起的一些问题,并针对我们在开发包括测试和性能分析在内的应用程序时应该遵循的最佳实践给出建议。

第2章讨论测试,了解测试和测试工具的当前状态。还介绍一个小而强大的测试概念——断言,我们将在本书的其余部分大量使用它,以确保代码完成我们希望它完成的事情(有时是为了证明它不应该这样做!)。

有了这些工具,第3章开始我们开始涉足语言基础,首先要彻底研究JavaScript中的函数(function),这可能会出乎大家意外之外。虽然你可能希望对象(object)是首先关注的内容,但object是对函数的深入理解,并且JavaScript是一种函数式语言,其可以让我们从普通的JavaScript程序员开始转变成JavaScript忍者!

第4章还是继续介绍函数,将把在第3章中学到的基础知识应用于我们在创建应用程序过程所面临的问题上。我们将探讨递归,不只是因为它本身的含义,而是因为我们可以通过检测递归学到更多关于函数的知识——我们将学习如何利用JavaScript的函数式编程特性让代码变得优雅,同时更加强大和简洁。我们将学习如何处理可变参数列表,以及在非原生支持方法重载的面向对象概念的语言中重载函数的方式。

第5章是大家可以从本书中学到的最重要概念之一的主题:闭包。函数式编程中的关键概念——闭包,允许我们对在程序中声明和创建的对象作用域进行细粒度控制。这些作用域的控制是JavaScript忍者编写代码的关键因素。即使不阅读本章后面的内容(但我们希望大家不要这样做),编程水平也会比刚开始学习时要好很多。

第6章解决对象问题,通过函数的prototype属性,我们可以学习创建对象的模式,我们将学习如何将对象绑定到它们定义的函数上——这是我们首先讨论函数的其中原因之一。

第7章主要是正则表达式,正则表达式是该语言常常被忽视的一项功能,如果正确使用,它可以完成很多行代码完成的工作。我们将学习如何构建并使用正则表达式,以及如何利用正则表达式及其相关方法优雅地解决一些反复出现的问题。

第二部分语言基础将在第8章结束,在本章我们将学习定时器和间隔定时器是如何在JavaScript的单线程特性中工作的。HTML5承诺使用Web workers为我们减少单线程限制,但大多数浏览器还无法做到,几乎所有现有的JavaScript代码都取决于对JavaScript单线程模型的深入理解。

第三部分从第9章开始,我们打开JavaScript运行时代码求值的黑盒子。我们来了解求值代码的各种方式,包括在我们的选择范围内怎样做是安全的。我们将讨论几个实例,比如JSON求值、元语言(又名领域特定语言)、压缩和混淆,甚至是面向方面编程。

在第10章中,我们将研究有争议的with声明,用于在作用域内缩短引用。无论你是with爱好者还是批评者,它都存在于大量的代码中,不管你认为它是炸弹还是令人憎恶的事物,都应该要理解它。

第11章的主题是处理跨浏览器问题。我们将研究5个与这些问题有关的关键开发问题:浏览器差异、错误和bug修复、外部代码和标记、缺失的功能以及回归。详细讨论特性模拟和对象检测等策略,以帮助我们应对这些跨浏览器挑战。

第12章的重点是处理元素特性(attribute)、属性(property)和样式(style)。虽然各种浏览器在如何处理这些元素方面的差异随着时间的过去会慢慢融合,但仍然有许多棘手的问题,本章将讲述如何解决这些问题。

第13章总结了第三部分内容,深入研究浏览器中的事件处理,以及创建能够以浏览器不可知方式处理事件的统一子系统方式。这包括给浏览器添加其无法提供的功能,如自定义事件和事件委托。

在第四部分中,我们加快进度,深入研究由jQuery等JavaScript库的核心内容引出的主题。第14章将讨论如何构建DOM操作API,在运行时操作文档对象模型,包括向DOM注入新元素的难题。

最后,在第15章中,我们将讨论如何构建CSS选择器引擎以及对选择器进行解析和求值的不同方式。这一章不适合胆小者,但可以用它来测验你是否能成为忍者。

清单或文本中的所有源代码都是采用固定宽度字体,将其与普通文本分离。文本中的方法和函数名、属性、XML元素和特性也采用相同的字体。

在某些情况下,原始源代码被重新格式化来适应页面。一般来说,编写原始代码时要考虑页面宽度限制,但有时你会发现本书中的代码和源下载提供的代码之间的格式有一点不同。在极少数情况下,不改变其意义,长长的代码行无法重新格式化,本书清单包含行接续符标记。

代码注释伴随有许多列表,用于突出重要概念。在许多情况下,数字编号对应着文本中的解释。

本书中所有运行示例的源代码(以及一些从未进入文本的额外代码)可以在本书的网页www.manning.com/SecretsoftheJavaScriptNinja上下载。

本书的代码示例按章节分类,每一章有单独的文件夹。布局由本地Web服务器来完成,如Apache HTTP服务器。简单将下载的代码解压缩到所选择的文件夹,并将该文件夹设置成为应用程序的根目录。

除了少数例外,大多数例子都不需要使用Web服务器,可以直接加载到浏览器中执行。

所有的例子都在各种现代浏览器中测试过(2012年中期),包括Internet Explorer 9、Firefox、Safari和Google Chrome。

作者和Manning出版社邀请你访问Manning出版社运营的本书论坛,在那里你可以评论本书,询问技术问题,并获得作者和其他用户的帮助。访问和订阅论坛,在浏览器中登录www.manning.com/SecretsoftheJavaScriptNinja,然后单击作者在线链接。这个页面提供有关如何注册登录论坛、可以获得哪些帮助以及论坛行为规则的信息。

Manning的承诺,是为读者提供一个场所,让各位读者以及读者和作者之间进行有意义的交流。Manning不要求作者的参与次数,对本书论坛的贡献仍是自愿的(无报酬)。我们建议大家试着询问作者一些具有挑战性的问题,以免他们转移兴趣!

只要本书在发售,在线交流论坛和先前讨论的帖子都可以在出版商的网站上进行访问。

本书封面上的图像是“能乐剧演员,武士”,19世纪中期一位不知名的日本艺术家制作的木刻版画。Noh(能乐剧)衍生自日语:天赋或技能,是从14世纪就开始出现的一种经典音乐剧。许多人物都戴着面具,男性扮演男性和女性角色。日本数百年来的英雄人物、武士,经常出现在表演中。在该版画中,精致的服装和威武的武士展示了这位艺术家的精湛技术。

武士和忍者都是日本艺术作品中善于打斗的勇士,他们非常勇敢和精明。武士是精英士兵,受过良好教育,文武双全,武士道是他们必须严格遵守的原则,自10世纪开始代代相传。他们来自贵族和上层阶级,相当于欧洲骑士。战争时,大批武士穿着精致的盔甲和彩色的服装,震慑住对方。忍者是靠武术技能选出,而不是社会地位或教育。他们穿着黑色服装,蒙面,单独或一小组出动,以诡计和隐身攻击敌人,千方百计完成任务,他们唯一的编码是保密的。

封面插图是由Manning的一位编辑多年来收集到的三个日本人物版画中的一个,当我们在为本书寻找忍者封面时,这幅引人注目的武士版画受到了我们的关注,它的细节刻画得很精致,色彩鲜明,生动地描绘了一位威武的战士志在必得的情形。

有时候我们很难区分两本计算机图书,Manning非常有创意,用200年前的插图做计算机图书的封面,这些插图描绘了世界各地的丰富多样的传统服装,印刷在封面上为其重新带来活力。


本书的这部分内容将奠定JavaScript忍者训练的基础。

在第1章中,大家将了解阅读本书后我们要做到什么,以及JavaScript开发人员要操作的框架环境。

第2章讲述测试为什么如此重要,并提供对一些可用测试工具的简单调查。然后我们会开发一些令人叫绝的简单测试工具,从而在余下的阅读培训中进行使用。

阅读完这部分内容后,你将可以开始准备训练成为一名JavaScript忍者了!


本章涵盖以下内容:

如果你正在阅读本书,应该知道,没有什么简单方法可以创建有效且跨浏览器的JavaScript 代码,除了编写整洁代码的常规挑战外,我们还要额外应对各种浏览器的差异和复杂性。为了应对这些挑战,JavaScript开发人员通常使用JavaScript库来实现通用和可重用的功能。

这些库虽然在方法、内容和复杂性方面有很大差异,但唯一不变的是:它们都需要简单易用,产生最少的开销,并能兼容所有浏览器,这些都是我们所希望的。

显而易见,通过了解如何构建最优秀的JavaScript库,可以为我们提供很好的洞察力,从而编写自己的代码来实现这些目标。本书力图揭示这些世界级代码所使用的技术和秘密,并将之聚集成一个单一的资源。

通过本书,我们将研究创建这些流行JavaScript库所使用(或即将使用)的技术。让我们开始了解这些库!

创建现代JavaScript库所用到的技术和实践是我们在本书中所关注的焦点。我们要选择一个最重要的库,当然就是jQuery,其已经跃升为目前最普遍使用的JavaScript库了。

jQuery(http://jquery.com)由John Resig创建,并在2006年1月发布。jQuery将用于匹配DOM内容的CSS选择器进行了普及。在众多功能中,它还提供了DOM操作、Ajax、事件处理以及动画功能。

jQuery已经主导了JavaScript库的市场,它被用于成千上万的网站,数以百万计的用户与之交互。通过大量的使用和反馈,该库一直在精练——继续优化——成为目前我们正在使用的最优代码。

除了研究jQuery示例代码以外,我们也会了解以下库所利用的技术。

这些库都经过了全面的构建并且解决了目标问题。基于这些原因,这些库对于我们进一步分析并理解代码库的基础建设,从而洞察世界级JavaScript库建设的过程打下了良好的基础。

但是这些技术,并不只用于构建大型库;它们也可以应用于所有的JavaScript代码,且无论代码大小。

一个JavaScript库的组成可以分为如下三个方面。

针对每个库,我们会仔细分析这三个方面,从而收集整理完整的知识体系,以便创建自己的高效JavaScript代码。

很多JavaScript程序员,在工作中不断进步,直到能够熟练使用大量的JavaScript语言元素,包括对象、函数(如果他们始终关注编码趋势)甚至是匿名内联函数。然而,在许多情况下,这些技巧可能并没有超出基础水平。此外,这些程序员,通常对JavaScript中闭包(closures)的目的和实现有着非常匮乏的理解,而闭包从根本上例证了函数对于该语言的重要性。

JavaScript中,对象、函数和闭包之间有着很密切的关系(如图1.1所示)。理解这三个概念之间的牢固关系,可以大大提高我们的JavaScript编程能力,为我们进行任意类型程序的开发打下坚实的基础。

图1.1 JavaScript中,对象、函数和闭包之间的密切关系

很多JavaScript开发人员,尤其是有面向对象背景的开发人员,可能会更多地关注对象,但却没有了解函数和闭包对于整个程序的作用。

除了这些基本概念,还有两个JavaScript特性远远未被充分利用:定时器和正则表达式。这两个概念,几乎在任何程序的JavaScript代码中都有,但由于易于被误解,因此它们并没有发挥全部潜力。

熟练掌握定时器如何在浏览器内运行(通常很神秘的),可以让我们有能力解决复杂的编码任务,如长时间运行的计算和平滑的动画。而理解正则表达式是如何工作的,可以让我们简化原本相当复杂的代码段。

作为JavaScript语言之旅的另一个高潮,我们将研究第10章中的with语句,以及第9章中有争议的eval()方法——两个重要但是具有争议的语言特性,这两个特性已经被滥用、误用,甚至有很多JavaScript程序员对其怨声载道。

注意:

持续关注Web开发技术发展趋势的人会知道这两个主题是有争议的,在未来版本的JavaScript中会被弃用或者被限制使用。

但由于在现有代码中可能会遇到这些概念,所以即使在将来的代码中不使用它们,理解它们也是非常重要的。

观察一些高级JavaScript程序员的工作,我们将会看到,恰当使用一些高级语言特性可以创建一些神奇的代码片段,而其他方式则往往不太可能。在很大程度上,这些高级特性也可以用于一些有趣的元编程练习,将JavaScript代码编写成任意我们想要的。

学习如何高效使用高级语言特性,以及如何发挥其最大优势,将代码质量提升到更高的水平。提升我们运用这些概念和特性的能力,提高我们的理解力,熟练掌握如何创建任意类型的JavaScript应用程序。这些基础知识,将为我们开始编写稳定跨浏览器代码的道路奠定坚实的基础。

完善JavaScript编程技能将引导我们不断前行,尤其是目前,除了浏览器端以外,JavaScript还能够使用Rhino、V8或Node.js库等JavaScript引擎在服务器端运行。但开发基于浏览器的JavaScript应用程序(这也是本书的重点)时,越早越好的是,我们首先要应对:浏览器及其令人恼火的问题和矛盾。

理想世界中,所有的浏览器中都没有bug,并且支持以一致的方式支持Web标准,但是我们都知道我们并不生活在这种世界里。

近来浏览器的质量已经有了大大改善,但仍有一些bug、缺失的API和不同浏览器的特定缺陷,我们需要解决这些问题。制定解决这些浏览器问题的综合性策略并熟悉不同浏览器之间的区别和缺陷,和精通JavaScript本身同等重要。

对于这些差异,在编写浏览器应用程序或JavaScript库时,决定支持哪些浏览器是一个重要考虑事项。我们可能想支持所有的浏览器,但却受限于开发和测试的资源限制。那么,我们如何决定支持哪些浏览器,支持到什么程度?

有一个方法,是来自古老Yahoo!的一个松耦合方式,称为分级浏览器支持(graded browser support)。在这种技术中,我们创建一个浏览器支持矩阵,作为记录浏览器和其平台的重要性的快照。

在这样一个表格中,我们在一个轴上列出目标平台,在另外一个轴上列出浏览器。然后,在每个单元格中,对每个浏览器/平台组合,我们给出一个“等级”(从A到F,或者是其他能够满足我们需要的评分系统)。表1.1展示了一个这样的例子。

注意,我们还没有填写任何等级。如何对特定平台和浏览器分配等级,完全取决于项目的需要和需求,以及其他重要的因素,例如目标受众的组成。使用这种方式,我们制定出相应平台/浏览器重要性的等级,并将这些信息和成本进行结合,尝试找出最优化的浏览器支持。我们将在第11章更深入地探索这些内容。

表1.1 一个假设的“浏览器支持矩阵”

Windows OS X Linux iOS Android
IE 6 N/A N/A N/A N/A
IE 7,8 N/A N/A N/A N/A
IE 9 N/A N/A N/A N/A
Firefox N/A
Chrome
Safari N/A N/A
Opera

由于支持大部分的平台和浏览器组合是不切实际的,因此我们必须权衡支持各种浏览器的成本与收益。任何类似的分析,都必须要考虑多个因素,主要有如下几点。

第一点是主观的,只有具体项目才能够确定。第二点是市场份额,可以通过互联网信息得到。支持每个浏览器的工作量,可以通过考虑该浏览器的功能和对现代浏览器标准的遵守情况进行粗略估计。

图1.2所示的图表,展示了主流浏览器的使用情况(信息来自2012年8月的StatCounter)以及我们对排名靠前的桌面浏览器开发成本的个人建议。

图1.2 各种桌面浏览器的支持成本与收益分析,揭示了我们要努力的方向

图表以“收益”与“成本”的方式进行展示,大概一看就可以知道怎么做“最划算”。跳出该图表,如下还有几点要注意的事项。

图1.3 移动市场,开发成本和收益相当,实际源于统计数据

看一下移动市场,情况就完全不同了,如图1.3所示。

当然,任何事情都不是那么枯燥。也许更恰当的说法是,好处比成本更重要,但这最终要看决策者的选择,他们要考虑市场需求和其他业务问题等因素来制定决策。但量化成本和收益是做出这些重要支持决策的一个良好起点。

另外,要注意,市场份额和支持成本的变化是很迅速的。密切关注像http://gs.statcounter.com这样的网站不失为一个明智的预防措施。

资源受限组织的另一个潜在因素是开发团队的技能。开发应用程序的主要原因就是让最终用户使用,开发人员可能需要发展必要的技能来开发该应用程序,以满足最终用户的需求。在成本分析阶段就需要考虑这些因素。

跨浏览器开发的成本,主要取决于开发人员的技能和经验,而本书的目的就是提高开发人员的技术水平,所以让我们首先来看一下当前的最佳实践。

掌握JavaScript语言和跨浏览器编码问题是成为Web应用程序开发专家的重要条件,但它们并不是全部。要进军专家行列,还需要秀出以下很多开发人员之前都已经掌握的高质量代码。我们将在第2章深入研究这些被称为最佳实践(best practices)的特征,除了熟练掌握语言外,还包括如下元素。

在我们的编程过程中,时常遵守这些最佳实践是极其重要的;跨浏览器开发的复杂性也直接证明了这一点。让我们来看看这些实践。

在本书中,我们将使用大量的测试技术,以确保示例代码的运行符合我们的预期,同样也作为测试一般代码的示例。对于测试,我们将使用的一个主要工具是assert()函数,其目的是断言代码是true还是false。

该函数的一般形式是:

第一个参数是一个条件,应该是true,而第二个参数则是一个消息,在第一个参数不为true时进行显示。

考虑如下代码:

如果变量a的值不等于1,断言就会失败,这些过于戏剧性的消息就会显示。

注意,assert()函数并不是JavaScript语言的原生特性(一些像Java这样的语言,也提供这样的功能),所以我们会自己实现它。我们将在第2章讨论assert()函数的实现以及使用。

另一个重要的实践是性能分析。浏览器的JavaScript引擎在JavaScript本身的性能表现上取得了惊人的进步,但这并不是我们编写劣质和低效代码的借口。

我们将使用本书稍后的如下代码,收集性能信息:

上述代码中,我们在代码执行的地方记录时间戳:一个在代码执行开始前,一个在代码执行后。两个时间戳之间的差值告诉我们代码执行了多少时间,使用相同的方式,我们可以测量其他替代代码方案的执行时间。

注意我们是如何多次执行代码的;在本例中,我们执行的次数由maxCount表示。因为代码的单次操作执行太快而很难准确地测量,所以我们需要多次执行代码以获取可衡量的值。至于执行次数有多频繁,这个数可以是成千上万,甚至上百万,这取决于被测代码的性质。通过反复试验,我们可以选择一个合理的值。

这些最佳实践技术,以及在这个过程中我们将学到的其他实践,将极大地提高我们的JavaScript开发水平。用浏览器提供的有限资源开发应用程序,再加上浏览器功能和兼容性问题的日益复杂,因此掌握完整和强大的技能是非常必要的。

以下是我们在本章所学到的内容。

这些探索肯定会很有益且具有教育意义——让我们来享受这个过程吧!


本章涵盖以下内容。

为代码构建有效的测试套件是非常重要的,所以在我们进入任何编码之前,要首先对它进行讨论。和可靠的测试策略同样重要的是要对所有代码进行测试,外部因素有可能影响代码的操作效果这点十分重要,这正是我们在跨浏览器JavaScript开发时要面对的情况。

我们不仅要处理典型问题:确保代码质量,尤其是与多位同时编写一段代码的开发人员打交道时,并避免出现会破坏API的回归错误(所有程序员都需要处理的普通问题),还要处理:判断代码是否在我们选择支持的所有浏览器上都能正常运行。

在讨论第11章的跨浏览器策略时,我们将进一步深入讨论跨浏览器开发问题,但是现在,重要的是要强调测试的重要性和测试策略的定义,因为我们将在本书的剩余部分使用这些策略。

在本章中,我们将了解用于调试JavaScript代码的一些工具和技术,并基于这些结果生成测试用例,并构建测试套件,从而可靠地运行这些测试。让我们开始学习吧。

还记得调试JavaScript的时候要使用alert()来验证变量的值吗?不过,在过去几年里,调试JavaScript代码的能力已经得到了大大的改善,在很大程度上是因为Firefox上的Firebug开发扩展的普及。

所有主流浏览器都有类似的工具。

调试JavaScript有两个重要的方法:日志记录和断点。它们可以回答下面这个重要的问题(“我的代码发生了什么事?”),但两种方法是从不同的角度来解决这个问题的。让我们先看一下日志记录。

日志记录(logging)语句(如,在Firebug、Safari、Chrome以及新版本Opera中使用的console.log()方法)是代码的一部分(即使可能是暂时的),并且在跨浏览器场景上十分有用。我们可以在代码中记录日志,并且可以从所有现代浏览器的控制台上看到的日志消息中获益。

相对于古老的“添加alert函数”这种技术,这些浏览器控制台都极大地改进了日志记录过程。在不阻碍程序正常处理过程的情况下,所有的日志记录语句都能写入到控制台,并能立即或稍后获得显示——而有些事情是alert()函数无法做到的。

例如,如果我们想知道变量x在代码特定位置的值是什么?我们可能会这样写:

在启用了JavaScript控制台的Chrome浏览器上,上述代码的执行结果如图2.1所示。

图2.1 日志可以让我们看到代码在运行时的状态

在记录日志时,老版本的Opera实现了一个postError()属性方法。如果必须要在这些旧版浏览器中记录日志,我们可以采用温和、更高级别的日志记录方法,适用于所有的浏览器,代码如下所示。

注:如果不需要处理过时版本的Opera,可以忽略这些代码,放心地使用console.log()。

代码清单2.1 一个适用于所有现代浏览器的简单日志记录方法

提示:

欲了解更多内容信息,可以访问http://patik.com/blog/complete-cross-browser-console-log/查看代码清单2.1的更全面版本。

在代码清单2.1中,我们首先尝试使用绝大多数现代浏览器都能用的console.log()方法记录日志消息1,如果失败,将会抛出一个异常,然后我们捕获该异常2,继而再尝试使用Opera的专有方法记录该日志消息3。如果这些方法都失败了,我们重新回来使用古老的alert函数4

注意:

代码清单2.1使用了JavaScript Function()构造器的apply()和call()方法接收传递的参数进行日志记录。Function()的这些方法用于帮助我们进行精确控制JavaScript函数的调用,在第3章,我们将会看到更多相关内容。

在代码运行时,通过记录日志查看程序运行状态是很好的做法,但有时我们要暂停代码的运行,并需要查看一下此时的相关信息。

这就是断点要做的。

断点(breakpoint)是一个比日志记录更复杂的概念,但它比日志有一个更显著的优势:它能在特定的代码上暂停脚本的执行,从而暂停浏览器运行。这使得我们可以在该断点处,随意查看任意代码的状态。其中包括所有可访问的变量、上下文以及作用域链。

如下所示,假设有一个页面,使用我们的新log()方法记录日志。

代码清单2.2 使用自定义log()方法的简单页面

如果我们使用Firebug在代码清单2.2的注释行1设置一个断点(在脚本显示的行号上进行单击),刷新页面重新执行代码,调试器就会在这一行停止执行,并向我们展示图2.2所示的效果。

图2.2 断点允许我们在特定代码上暂停执行,从而查看此时的状态

注意,右边的窗格允许我们查看代码运行的状态,包括x的值。调试器会在实际要执行的断点前暂停执行;在本例中,log()方法还没有被执行。

如果我们想使用新方法进行调试,可以单步执行该方法,一探究竟。单击“进入(step into)”按钮(最左边的黄金箭头按钮)可以让调试器开始执行新方法的第一行,然后我们会看到图2.3所示的内容。注意显示的状态已经改变,从而让我们可以查看log()方法执行的新状态。

图2.3 单步执行该方法,可以让我们看到代码执行的新状态

任何具有断点功能的全功能调试器都高度依赖于执行该调试器的浏览器环境。鉴于这个原因,上述开发者工具才会被创建;否则,它们的功能也不会实现。这是一个对整个Web开发社区的伟大贡献和救济,所有主流的浏览器实现者都可以创建有效的实用工具程序以便调试。

调试代码不仅符合其主要和明显目的(检测并修复bug),而且也可以帮助我们获取当前生成高效测试用例的最佳实践。

Robert Frost曾写道:篱笆筑得牢,邻居处得好,Web应用程序也是如此,不管是何种编程准则,好的测试铸就好的代码。注意对这个“好”字的强调。如果测试用例的构建很差,它很有可能只是大量的测试套件,不会真正帮助我们提高代码质量。

优秀的测试用例具有三个重要特征。

有很多方法可以用于构建测试,有两种主要的方法分别是解构型测试和构建型测试:

让我们来看一个构建型测试的例子。

创建一个精简的测试用例时,我们可以从几个已经包含最小功能的HTML文件开始。甚至不同的起始文件可以包含不同的功能,例如,一个文件用于DOM操作,一个文件用于Ajax测试,另外一个则用于动画,等等。

举个例子,如下代码清单展示了一个简单的用于测试jQuery的DOM测试用例。

代码清单2.3 一个精简的用于jQuery的DOM测试用例

要使用干净的代码副本生成一个测试用例,我们可以使用shell脚本签出jQuery库,复制测试用例,并构建测试套件,如下所示:

将上述脚本保存为一个gen.sh的文件,并使用如下命令行执行:

该命令将可以让我们从Git库的dom.html文件中获取DOM测试用例。

另外一种方式是使用一个预先构建的用于创建测试用例的服务。其中一个叫JS Bin(http://jsbin.com/),它是一个用于构建测试的简单工具,可以生成一个唯一的url地址——甚至可以引用一些最受欢迎的JavaScript库的副本。JS Bin的示例如图2.4所示。

图2.4 JS Bin网站的截图

一旦具备了创建测试用例所需的工具和知识以后,我们就可以为这些测试创建一些测试套件,从而使得反复运行这些测试变得更加容易。让我们来研究一下。

测试套件应该作为基本开发流程的一部分,所以应该选择一个非常适合自己代码风格和代码库的测试套件。一个JavaScript测试套件应该满足一个唯一需求:显示测试的结果,以便很容易地确定哪些测试通过的,哪些是失败的。测试框架可以帮助我们达到这一目标,除了创建测试并将其组织到测试套件中以外,不用再担心别的事情。

根据测试的需要,我们可以从JavaScript测试框架中找到很多功能。其中一些功能包括:

一项非正式的调查,试图统计人们在日常开发过程中使用哪种JavaScript测试框架,其结果非常具有启发性。图2.5描述的令人沮丧的事实是,很多人根本不测试。通常情况下,大家会很容易认为非测试人员的比例实际上是更高的。

图2.5 大多数JavaScript开发人员根本不做测试

注意:

如果对原始结果有兴趣,请访问http://spreadsheets.google.com/pub?key=ry8NZN4-Ktao1Rcwae-9Ljw&output=html.

另一个从该结果得出的观点是,绝大多数的脚本编写者,在编写测试用例时都选择如下四个工具中的一个:JsUnit、QUnit、Selenium以及YUI Test。测试工具的前十大“赢家”,如图2.6所示。

图2.6 大多数懂测试的开发者选择少量的测试工具

这是一个有趣的结果,其表明没有一个有绝对优势的测试框架。但更有趣的是有相对较少用户的一次性框架的数量,如图2.6所示。

应该注意的是,从头开始编写一个测试框架是很容易,如果要更好地理解一个测试框架是如何实现的,这是一个好办法。这是一个特别有趣的练习,因为在编写一个测试框架时,我们通常是要处理纯JavaScript,而无需过多担心跨浏览器的问题。除非我们想模拟浏览器事件,如果是这样(尽管我们将在第13章解决这个问题)祝你好运!

根据图2.6显示的结果,许多人得出同样的结论,并编写了大量的一次性框架以适应自己的特殊需要。虽然可以编写一个专有的单元测试框架,但很有可能我们想用的是预先构建的框架。

一般的JavaScript单元测试框架会提供一些基本组件:一个测试运行器、测试分组以及断言。还有一些测试框架提供了异步运行测试的功能。让我们简要看一些最受欢迎的单元测试框架。

QUnit最初是用于测试jQuery的单元测试框架。它的发展已经超出其最初的目标,目前是一个独立的单元测试框架。QUnit主要是为单元测试提供一个简单的解决方案,提供最小但却易于使用的API。

QUnit的特点如下:

更多信息,请访问http://qunitjs.com

YUI Test是Yahoo !构建并开发的测试框架,于2008年10月发布。为了配合YUI3的发布,2009年YUI Test被完全重写。YUITest提供了大量的特性和功能,以确保覆盖代码库所需要的任何单元测试用例。

YUI Test的特点如下:

更多信息,请访问http://developer.yahoo.com/yui/3/test/

JsUnit是流行的Java JUnit测试框架在JavaScript语言上的实现。尽管它仍然是最流行的JavaScript单元测试框架之一,但也是最古老的(无论是代码年龄还是代码质量)。该框架最近没有进行太多更新,所以要测试大家熟知的现代浏览器的代码,JsUnit可能不是最好的选择。

更多信息,请访问www.jsunit.net/。

根据JUnit的主页信息,Pivotal Labs团队现在正专注于一个名为Jasmine的新测试工具。更多信息,请访问http://pivotallabs.com/what/mobile/overview

另外一个需要了解的测试工具是TestSwarm,一个分布式的持续集成测试工具,最初由John Resig开发,目前已成为Mozilla实验室的一部分:

https://github.com/jquery/testswarm/wiki.

接下来,我们要看一看如何创建测试套件。

测试套件的主要目的是聚合代码中的所有单个测试,将其组合成为一个单位,这样它们可以批量运行,提供一个可以轻松反复运行的单一资源。

为了更好地理解测试套件的工作原理,我们有必要了解如何构建一个测试套件。或许有些出人意料,构建JavaScript测试套件确实很容易。大约只需要40行代码就可以构建好一个功能。

人们可能会问“为什么要创建一个新的测试套件?”,大多数情况下,可能没有必要编写自己的JavaScript测试套件。目前已经有大量的高质量测试套件可供选择。但是,构建自己的测试套件可以作为很好的学习经验,尤其是了解异步测试是如何工作的时候。

单元测试框架的核心是断言方法,通常叫assert()。该方法通常接收一个值——需要断言的值,以及一个表示该断言目的的描述。如果该值执行结果为true,换句话说是“真值”,断言就会通过;否则,断言就会被认为是失败的。通常用一个相应的通过(pass)/失败(fail)标记记录相关的信息。

从下面的代码清单中,可以看到一个简单的实现。

代码清单2.4 JavaScript断言的一个简单实现

名为assert()的函数1极为简单。它创建一个新<li>元素并包含描述,分配其一个pass或fail样式,该样式取决于断言参数的值(value),并将新元素附加到body4内的一个列表元素上。

该测试套件包括两个微不足道的测试3:一个总是成功,另一个总是失败。pass和fail的样式规则2,则使用颜色在视觉上表示成功或失败。

该函数很简单,但对于未来开发,它将会作为良好的构建块,在本书中,我们将使用这个assert()方法测试不同的代码片段,验证代码的完整性。

简单的断言是很有用的,但真正发力,却是在测试上下文中将它们组合在一起形成测试组的时候。

执行单元测试时,一个测试组可能代表一组断言,因为它们在我们的API或程序里关联的是一个单一的方法。如果是在做行为驱动开发,测试组将通过任务集成断言。不管是哪种方式,其实现实际上是相同的。

在示例测试套件中,测试组将单个断言的结果插入到结果中。此外,如果任何断言失败,那么整个测试组标记为失败。如下代码清单的输入相当简单——在实践中动态控制层级被证明是非常有用的(如果测试失败的话,可以收缩/展开测试组,并且过滤测试)。

代码清单2.5 测试分组的实现


如代码清单2.5中看到的,其代码实现和基本的断言日志记录真的是没有太大区别。一个主要的区别是包含一个results变量,该变量持有当前测试组的引用(这样可以正确插入断言)。

除了简单的测试代码以外,测试框架的另外一个重要方面是异步操作的处理。

很多开发人员在开发测试套件时遇到的一个艰巨而复杂的任务是对异步测试的处理。这些测试的结果在一段不确定的时间后会返回,这种场景的常见例子如Ajax请求和动画。

处理该问题的方式通常是过度设计,并且设计的要比实际需要的更复杂。处理异步测试,我们需要遵循一些简单的步骤。

1.将依赖相同异步操作的断言组合成一个统一的测试组。

2.每个测试组需要放在一个队列上,在先前其他的测试组完成运行之后再运行。

因此,每个测试组必须能够异步运行。

让我们来看一个下面清单中的例子。

代码清单2.6 简单的异步测试套件



让我们分解代码清单2.6中的功能。有三个公开函数:test()、pause()和resume()。这三个函数有以下功能。

内部的实现函数runTest(),在测试排队时从列中移除时进行调用。它用于检查当前套件目前是否没被暂停以及队列中是否有测试任务,一旦满足情况,将从队列中取出一个测试并尝试执行它。此外,测试组完成执行之后,runTest()会检查该套件目前是否暂停了,如果没暂停(这意味着,测试组中只有异步测试),runTest()将开始执行下一组测试。

我们将在第8章仔细研究延迟执行,其重点是定时器,我们将深入研究有关JavaScript代码延迟执行的细节。

在这一章中,我们已经学习了一些与调试JavaScript代码相关的基本技术,以及基于这些结果构建简单的测试用例。

现在可以开始准备训练了。喘口气,然后继续训练,第一堂课上的这些内容可能不是你所期望的!


相关图书

深入浅出Spring Boot 3.x
深入浅出Spring Boot 3.x
JavaScript核心原理:规范、逻辑与设计
JavaScript核心原理:规范、逻辑与设计
JavaScript入门经典(第7版)
JavaScript入门经典(第7版)
JavaScript函数式编程指南
JavaScript函数式编程指南
PHP、MySQL和JavaScript入门经典(第6版)
PHP、MySQL和JavaScript入门经典(第6版)
JavaScript学习指南(第3版)
JavaScript学习指南(第3版)

相关文章

相关课程