书籍作者:Evan | ISBN:9787519823542 |
书籍语言:简体中文 | 连载状态:全集 |
电子书格式:pdf,txt,epub,mobi,azw3 | 下载次数:6021 |
创建日期:2021-02-14 | 发布日期:2021-02-14 |
运行环境:PC/Windows/Linux/Mac/IOS/iPhone/iPad/Kindle/Android/安卓/平板 |
本书作者向你展示如何识别糟糕的代码,然后通过多种重构方法来改进这些糟糕的代码。采用的技术从重命名变量到运用函数式和面向对象编程的原则。如果你想在前后端写出更好的JavaScript代码,那么本书必不可少。利用重构来重新组织现有的代码,而不改变它的行为。
了解重构与质量之间的关系。
探索现今使用的不同版本的JavaScript。
创建自动化测试以确保你的代码可以工作,并且找到被遗漏掉的错误。
了解如何重构简单的JavaScript结构、函数以及对象。
运用面向对象和函数式编程原则来重构你的代码。
重构异步JavaScript的检验方法。
Evan Burchard是一位Web开发顾问,同时也是《The Web Game Developer’s Cookbook》的作者。在线下,他设计了一个屡获殊荣的体感游戏,包括堆积真实的冰块,他也定期继续他走遍美国的计划。
如果你的JavaScript代码很糟糕,框架只能为你提供有限的帮助。无论使用什么框架、“编译成JS”的语言或者库,如果底层的JavaScript代码质量很糟糕的话,错误和性能问题将始终存在。通过本书,你将学到如何测试和重构现有的代码,以帮助降低复杂性、提高可读性并提高对代码库的信心。
前言
欢迎阅读本书。在本书中,我们将探讨如何编写更好的JavaScript,从经典的重构技术中获取灵感,同时探索各种风格的编程方式。
为什么写本书
不管你喜欢与否,JavaScript都不会消失。无论使用什么框架、“编译成JS”的语言或库,如果底层的JavaScript代码质量很糟糕的话,错误和性能将会是始终存在的问题。重写,包括移植到当前热门的框架,是非常昂贵且不可预测的。错误不会凭空消失,它们仍会在新的代码中重现。如果把事情变得更复杂,至少要将功能暂时丢弃掉。
本书为如何最好地避免不理智地写JavaScript提供了清晰的指导。糟糕的代码不必保持这种方式。让它变得更好并不需要让人望而生畏,也不会太昂贵。
本书的读者对象
本书是写给那些有写糟糕代码经验,并想要写更好代码的人。也是写给那些在前端或者后端写JavaScript的人。还是写给那些写JavaScript以及由于JavaScript对浏览器平台的垄断而被困住了的人。
你如果是一个纯粹的初学者,那么你可能首先要写几个月糟糕的代码。如果你不想写更好的代码,你可能没有读完这本书的耐心。如果这两种情况都不能描述你,那我们继续吧。
有趣的是,有许多努力使JavaScript变得更好,同时也有其他努力使它过时。写优秀的和糟糕的JavaScript代码的方法在持续扩展。框架对于处理复杂性起很大作用,但是局限于框架的程序员会被限制住。如果你发现你(或者你的代码库)在一个框架之外(或者在更混乱的边缘)很难工作,本书应该会给你提供新的思路去处理你的工作。
如果你在测试、调试或代码置信度方面有困难,本书对你是有帮助的。
我们大多数人没有在完美的代码库上工作,特别是在JavaScript中,工程师可能主要使用Ruby、Python、Java等。本书所做的是帮助你识别代码库中哪些部分是糟糕的,同时提供了大量的改进选择。
如何使用本书
第1~5章描述了JavaScript、重构、质量、置信度与测试之间的相互作用。在很多书中,通常将测试放在最后。在本书中,对于我们探索的代码类型,这是不合适的。测试对于置信度至关重要。置信度对于重构至关重要。重构对于质量至关重要,这也是我们的目标:
测试 → 置信度 → 重构 → 质量
JavaScript(及其生态系统)恰好提供了转换发生的空间,所以开篇这些章节必须包括对语言本身的探索。如果你对刚才描述的转换完全理解,你可以略读或跳过这些章节。虽然不推荐,但这是你的书,所以你可以随意使用它。如果你认为它最适合用作门挡,或用来取暖或做某种牺牲,那就去做吧。如果你确实发现了本书有非常规用途,给我发图片或视频:http://evanburchard.com/contact或在Twitter和GitHub上@evanburchard。
我也可以把电子版烧掉或用作门挡吗?
不幸的是,不行。但是,由于本书符合知识共享许可协议,你可以自由地分享HTML版本以及任何其他在http://refactoringjs.com上的文件的链接。
在第5章之后,内容变得更难,尤其是如果你跳过了第1~5章。有更多的代码需要写和跟随。在第6章和第7章,我们将讨论重构函数和对象,我们不会回避一些更复杂的JavaScript代码。总的来说,这些章节的目标是为改进代码提供选择,而不需要从根本上改变接口。通过应用这两章中的技术,你将能够将混乱的代码库变成有良好质量基准的代码。
第8章将我们的架构扩展到包含(或避免)层次结构的视图。
第9~11章专门针对特定的主题(分别是设计模式、异步编程和函数式编程),它们可以让你的代码超越基准代码,这必然涉及更积极的变化。在第9章的设计模式中,我们认识到从JavaScript的面向对象的方面扩展和借鉴的方法,并覆盖了重构和面向对象编程(OOP)之间的历史联系。在第10章中,我们处理了许多JavaScript代码库同时做很多事情的现实情况。在第11章中,我们将通过几个库来体验函数式编程,这些库提供了超出标准数组函数(forEach、map、reduce等)所提供的接口。
从某种意义上来说,最后的三章脱离了我们最初的重构目标:在不改变接口的情况下改变实现细节。另一方面,这些接口都是有用的,有时是不可避免的。我们很容易发现自己为了性能而写异步代码。或者我们可能发现自己被困在一个代码库中,它在OOP 或函数式编程(FP)投入了大量好或不好的尝试。因此,无论是通过选择还是通过我们继承的代码,都是我们应该关注并改进的 JavaScript 的部分。如果你对代码库采用了完全不同的范式,那么本书大部分内容所说的不是你所做的“重构”。
如果我们想要严格控制它,这些章节仍然在它们的范式中重构(OOP到更好的OOP,异步到更好的异步,以及FP到更好的FP),如果我们想从最广泛的角度考虑我们的程序的执行(例如,运行node myprogram.js 作为输入并且“being satisfiedwith how it ran”作为输出),那么即使在不同的范式间切换,我们也可以重构。我鼓励你先尝试较小的增量更改,这会更容易测试并且让你更有信心。
引用William Opdyke关于重构的原始论文:
语义等价的这种定义允许在整个程序中进行更改,只要输入到输出值的映射保持不变。想象一下,在受重构影响的程序周围绘制一个圆。从圆外观察的行为不会改变。对于一些重构,圆包围了大部分或全部程序。例如,如果一个变量在整个程序中被引用,那么更改其名称的重构将影响大部分程序。对于其他重构,这个圆覆盖的面积要小得多;例如,当包含在一个函数中的某个函数调用被内联扩展时,只有一部分函数体会受到影响。在这两种情况下,关键思想是从圆外部观察,调用的操作结果(包括副作用)和圆外的引用都不会改变注1。
尽管我们可以自由地绘制圆的大小,我们常常看到“重构”这个词被随意使用,就好像它只意味着“改变代码”一样。正如我们在第1章所讨论的,它不是这样的。这在小规模的项目中很常见,比如我们浏览最多的页面。考虑第8~10章,首先作为架构的选择,其次在这些选择中创建更好的代码(安全且增量地)的可能性。例如,如果有人说“使用异步代码来重构”,这可能太宽泛了,以至于难以以安全且增量的方式执行。但如果你想到第9章给了你这样做的力量,我不能阻止你。现在这是你的书。
你可以绘制你想要的圆。
如果你对任何工具或概念感到困惑,你可能会发现附录是有帮助的。如果你正在寻找示例代码和其他信息,请访问本书的网站。你也可以在那里找到一个HTML版本的书,如果你喜欢这样阅读的话。
总之,本书用来了解:
? 重构。
? 测试。
? JavaScript。
? 重构与测试 JavaScript。
? 几个 JavaScript 范式。
? 使用这些 JavaScript 范式进行重构与测试。
或者(在成人监督下),书的纸质版可以用来生火并用于:
? 取暖。
? 抗议。
? 科技图书牺牲仪式。
http://refactoringjs.com/上的电子版文件可以按照知识共享许可限制的方式传播。
如果你有任何问题、疑问、抱怨或赞美,请随时通过我的网站联系我。
本书的一些术语
App,应用,程序
本书中的一些词是不精准的。App、应用、程序和网站大多数情况下是可以互换的。如果有任何困惑的地方,本书描述了提高JavaScript质量的基本原则,所以这些词不应该完全按照字面意义解读。也许你的代码是一个库或框架?无论如何,本书中的技巧应该都是适用的。
通过词语和图表提高包容性
本书中的一些词可能不会对每个人都具有包容性。我试图平衡他和她的使用,我意识到这并不是每个人理想的方式。虽然我更倾向于使用单数形式,但这不是出版商的准则。
此外,我(太晚)意识到我对图表的依赖,特别是在第5章中,这可能对有视力障碍的读者造成严重的伤害。如果你觉得你因为这个原因错过了任何内容,请随时向我提出任何问题。
用户
在本书中还有一个词我真的很讨厌,就是用户。它并不精确,并且还在创建者(开发者/ 设计者)和消费者(用户)之间拉开了一定距离。更精确和友善的词通常特定于问题域,否则我们会被像“人”或“使用程序/ 网站的人”之类的术语困住。如果没有比人或用户(甚至包括客户)更具体的术语,它可能暗示着商业模式纯粹是将人们作为数据销售,但这是另一个讨论。
关键是,在本书中使用术语用户来传达一个熟悉的概念:使用程序/网站的人。此外,还没有广泛和准确的术语来代替用户体验(UX)或用户界面(UI)的相关术语。我为了节省精力,只是在这里谈论它,而不是在几个地方解释这个问题,也没有使用非标准或特定的术语来解释常见的抽象概念。
无论如何,我完全赞同“数据达芬奇”Edward Tufte的话(及其含义):
只有两个行业将其客户称为用户:非法药物和软件公司。
有一个叫做“道德设计”的运动,希望能在某种程度上帮助行业摆脱这一术语(以及源于它的不合理的做法)。
第三方库和社区
尽管我非常努力地展示了最好的工具来说明重构和测试JavaScript的基本原理,但有时你会发现某个工具并不适合你。好消息是,JavaScript具有丰富的生态系统以供选择。我偏爱简单、灵活和职责单一的工具,但你可能会有不同的想法。在本书中,大型框架尤其没有被探究,因为它们往往有自己的其他工具的生态系统(通常它们本身相当活跃和多样)。我绝对会在你刚开始的时候推荐一个框架,但是它们在与基础语言的功能结合时才是最有用的,我相信本书在这方面会教你很多。
此外,每个工具、框架和库都伴随着社区和历史。正如我不相信任何一种工具能一直有效,我也不支持任何第三方代码或项目背后的社区。很多项目有行为准则,让你知道参与其中是否会让你愉快地利用你的时间。
API、接口、实现、“客户端代码”
这有点模糊,但我希望我能强调更多的不是对象的层次结构,而是一个设计良好的代码库接口的层次结构。当代码是一段简单的脚本时,我们希望它可以作为一个过程从上到下运行。随着代码库的成熟(通过设计),我们期望它在三个主要的层中发展(尽管这显然会扩展出更复杂的代码库)。
第一层在本书中被称为实现,是代码库深处的代码。对于重构,最重要的区别是实现层和下一层之间的区别。第二层可以称为接口或API ,描述了使用代码库作为模块时应该期望与之交互的“公有”函数和对象。第三层一般被称为客户端代码或调用代码。
它指的是与接口层交互的代码。这是使用模块的人写的代码,并且我们会写测试代码来测试接口层。
架构基础
在本书中,起初我们创建的程序非常没有条理,我们的重点(不管像OOP或FP这样的范式)在这三个层之间的划分。这使得代码是可测试的和可移植的。
如果你主要依赖于提供自己组织的框架,那么你可能不熟悉这个过程。
输入(非局部与自由变量)
贯穿全书(特别是第5章),我们区分三种类型的输入:
? 显式输入(传递给函数的参数)。
? 隐式输入(指代包含上下文对象、函数或类的this)。
? 非局部输入(函数或对象中使用的在其他地方定义的值)。
这里有两点要注意。首先,为了图解或其他原因,函数内创建的局部变量(或常量)不被认为是“输入”。其次,虽然本书使用非局部输入作为一个精确的术语,但更常见的名称是自由变量。然而,考虑到非局部输入可以是常量而不是变量,这样叫它是有点不精确。类似地,一些人使用术语绑定变量来指代我们所说的显式输入,在某种程度上,也指隐式输入。
本书约定
本书使用下列排版约定:
斜体(Italic)
表示新出现的术语、网址、邮件地址、文件名与文件扩展名。此外也被用于强调重点或对比。
等宽字体(Constant width)
用于程序列表,以及在段落中引用程序中的元素,比如变量或函数名、数据库、数据类型、环境变量、语句以及关键字。
等宽粗体(Constant width bold)
表示应由用户输入的命令或者其他文本。
等宽斜体(Constant width italic)
表示应由用户提供的值或者由上下文确定的值替换的文本。
表示提示或建议。
表示一般性说明。
表示警告或提醒。
使用示例代码
补充材料(示例代码、练习等)可以在https://refactoringjs.com下载。
这本书是帮助你完成工作的。通常,如果使用本书提供示例代码,你可以在程序和文档中使用它。除非你需要大段大段地复制代码,否则不需要联系我们获得许可。例如,使用本书中所提供的几个代码片段来写一个程序不需要得到我们的许可。但销售或发布O’Reilly图书配套的CD-ROM则需要O’Reilly出版社的许可。引用本书的示例代码来回答问题不需要许可。将本书中的示例代码大量放到自己的产品文档中是需要获得许可的。
如果你在使用示例代码时注明出处,我们会很感激,但这不是必要的。注明出处的形式包括标题、作者、出版社和ISBN。例如:“Refactoring JavaScript by EvanBurchard (O’Reilly). Copyright 2017 O’Reilly Media, 978-1-491-96492-7”。
如果你觉得对于示例代码的使用超出了上面所给出的许可范围,欢迎通过[email protected]联系我们。
本书的代码使用的工具可以在附录中找到,还有更多关于覆盖到的话题的信息。作为参考,本书使用的工具与版本是:
? node 6.7.0
? npm 3.10.3
? wish 0.1.2
? mocha 3.2.0
? deep-equal 1.0.1
? testdouble 1.10.0
? tape 4.6.3
? lodash 4.17.2
? assert 1.4.1
? underscore 1.8.3
? ramda 0.22.1
? sanctuary 0.11.1
以后的版本不太可能造成问题,但更早的版本可能会出现问题。在较低的版本中,特别是node,它不完全支持本书中的代码。
O’Reilly Safari
Safari(以前的Safari Books Online)是为企业、政府、教育工作者和个人提供的会员制的培训和参考平台。
会员能够访问由超过250个出版商提供的数以千计的图书、培训视频、学习路线、互动教程和策划的播放列表,包括O’Reilly Media、Harvard Business Review、PrenticeHall Professional、Addison-Wesley Professional、Microsoft Press、Sams、Que、Peachpit Press、Adobe、Focal Press、Cisco Press、John Wiley & Sons、Syngress、Morgan Kaufmann、IBM Redbooks、Packt、Adobe Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones & Bartlett和Course Technology等。
欲了解更多信息,请访问http://oreilly.com/safari。
联系我们
请将关于本书的意见和问题通过以下地址提供给出版商:
美国:
O’Reilly Media, Inc.
1005 Gravenstein Highway North
Sebastopol, CA 95472
中国:
北京市西城区西直门南大街2号成铭大厦C座807室(100035)奥莱利技术咨询(北京)有限公司
针对这本书,我们还建有一个网页,列出了有关勘误、示例和其他信息。可以通过以下地址访问这个页面:http://bit.ly/refactoring-js_1e。
如果对这本书有什么意见,或者要询问技术上的问题,请将电子邮件发至:[email protected]。
在Facebook上找到我们:http://facebook.com/oreilly。
在Twitter上关注我们:http://twitter.com/oreillymedia。
在YouTube上观看我们的视频:http://www.youtube.com/oreillymedia。
致谢
感谢我的家人支持我完成本书:母亲、父亲、Amy、Scott、Gretchen、Max 和 Jade。特别感谢帮助过我开始工作的人:Zeke Templin、Steve Souders、Mary Treseler、Simon St. Laurent和Tyler Ortman。
感谢给过我技术灵感和反馈的人:Jacob Barss-Bailey、Matt Blake、Charles Baakel、Stefano De Vuono和Ryan Duchin。
感谢O’Reilly的工作人员一直以来给予我的帮助:Annalis Clint、Nena Caviness、Michelle Gilliland、Rita Scordamalgia、Josh Garstka、Kristen Brown、Rebecca Demarest、Rachel Monaghan、Shiny Kalapurakkel,特别是我的编辑Nan Barber和Ally MacDonald。
感谢我的技术审稿人:Steve Suering、Shelley Powers、Chris Deely、Darrell Heath和Jade Applegate。
感谢那些所做的工作对我有帮助和启发的人:William F. Opdyke、Martin Fowler、KentBeck、John Brant、Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides、Douglas Crockford、Tony Hoare、Alexis Deveria、Addy Osmani、Robert Nystrom、BrianLonsdorf、Reginald Braithwaite、Miran Lipovaca、Kyle Simpson、Tom Stuart、MichaelFogus、David Chambers、Michael Hurley、Scott Sauyet、Yehuda Katz、Jay Fields、Shane Harvie、Russ Olsen、Joshua Kerievsky、James Halliday、TJ Holowaychuk、Justin Searls、Eric Elliot、Jake Archibald、Arnau Sanchez、Alex Chaffee、EricHodel、Sean Hussey、Brian Cardarella、Foy Savas、Katrina Owen和Bryan Liles。
特别感谢Axel Rauschmayer博士出色的工作,他为我们这些人解释了规范,他还为本书做了序。
嘘……嘿,读者!
我知道它看起来只是一个大名单,但是上面提到的人真的非常棒。附录中的资源也不如这个名单重要,这里面的很多人做了这些事情。搜索他们的名字会让你知道他们新的东西,这可能比他们的旧东西更好。快去查查这些人。
感谢TC39和MDN的所有人。
感谢我的狗和我散步,即使是我正处于什么东西的中间。
另外,也感谢每一位读者,谢谢你支持我的工作,如果你需要什么请联系我。
序
我仍然记得在1999年Martin Fowler的《重构:改善既有代码的设计》出版时读了这本书。这本书给了我一个启示:我从未见过代码被认为是可塑的。程序员倾向于从头开始重写代码库,但这本书认为可以通过小的、有原则的和比较安全的步骤来演进和清理现有的代码。在这样做的时候,测试提供了一张额外的安全网,使你能够自信地向前推进。我将始终遵循这本书中的一条建议,每当你写代码时,始终保持两种行为完全分开:实现新功能和重构现有的代码。如果这样做,你会避免同时做太多事情,并且会产生更少的错误。
《重构JavaScript》采用重构的思想,将其应用于JavaScript的世界。JavaScript的动态特性意味着与更多的静态语言(如Java)相比,你需要使用不同的重构技术。在Java中,你有静态类型。而且继承和多态被使用得很频繁。对于JavaScript,你通常依赖于静态检查工具(如ESLint和Flow),并可根据需要灵活调整对象。函数式编程技术也更受欢迎。此外,测试发挥了更重要的作用,但它们往往也更轻量级。对于所有这些问题以及更多内容(例如,异步代码),本书均已经涵盖了!
阅读愉快!
——Axel Rauschmayer
目录
序 1
前言 3
第1章 重构是什么? 13
你如何保证不改变行为? 13
如果不改变行为,重构的目的是什么? 18
重构是什么,不是什么 21
小结 22
第2章 你使用哪种JavaScript? 23
版本与规范 24
平台与实现 25
预编译语言 26
框架 27
库 29
你需要什么JavaScript? 29
我们在用什么JavaScript? 30
小结 30
第3章 测试 31
为什么测试 34
测试的多种方法 35
工具和流程 43
小结 52
第4章 测试实践 53
从零开始的代码 55
采用测试驱动开发的从零开始的代码 61
未经测试的代码与特性测试 80
调试和回归测试 85
小结 93
第5章 基本重构目标 95
函数块 98
输入 101
输出 106
副作用 109
上下文第一部分:隐式输入 110
上下文第二部分:隐私 116
小结 128
第6章 重构基本结构 130
示例代码132
我们的信心策略 135
重命名 137
无用的代码 142
变量 148
字符串 157
使用数组:循环、forEach、映射 161
小结 167
第7章 重构函数与对象 168
示例代码(改进后) 168
数组和对象的替代品 171
测试我们所拥有的 179
提取函数185
用全局对象简化API 192
小结 246
第8章 层次结构中的重构 247
关于“CRUD应用”和框架247
构建层次结构 248
破坏层次结构 256
继承与结构 264
Has-A关系 270
继承反模式 271
小结 280
第9章 重构到面向对象模式 281
模板方法282
策略 285
状态 288
空对象 295
包装(装饰器和适配器) 302
外观 310
小结 313
第10章 重构异步 315
为什么用异步? 315
修复金字塔厄运 318
回调和测试 326
Promises 330
小结 336
第11章 函数式重构 337
函数式编程的限制和好处 338
基础 344
高级基础358
Burritos 369
学习和使用Burritos 383
从OOP迁移到FP 385
小结 390
第12章 结论 392
附录A 进一步阅读和资源 393