├── .gitignore
├── .nojekyll
├── 0.md
├── 1.md
├── 10.md
├── 11.md
├── 12.md
├── 13.md
├── 14.md
├── 15.md
├── 16.md
├── 17.md
├── 18.md
├── 19.md
├── 2.md
├── 20.md
├── 21.md
├── 3.md
├── 4.md
├── 404.html
├── 5.md
├── 6.md
├── 7.md
├── 8.md
├── 9.md
├── CNAME
├── Dockerfile
├── LICENSE
├── README.md
├── SUMMARY.md
├── asset
├── docsify-apachecn-footer.js
├── docsify-baidu-push.js
├── docsify-baidu-stat.js
├── docsify-clicker.js
├── docsify-cnzz.js
├── docsify-copy-code.min.js
├── docsify.min.js
├── prism-darcula.css
├── prism-javascript.min.js
├── search.min.js
├── style.css
└── vue.css
├── cover.jpg
├── diff-en
├── 2ech0-3ech0.diff
├── 2ech1-3ech1.diff
├── 2ech11-3ech12.diff
├── 2ech12-3ech13.diff
├── 2ech13-3ech14.diff
├── 2ech14-3ech15.diff
├── 2ech15-3ech16.diff
├── 2ech16-3ech17.diff
├── 2ech17-3ech18a.diff
├── 2ech18-3ech18b.diff
├── 2ech2-3ech2.diff
├── 2ech20-3ech20.diff
├── 2ech21-3ech21.diff
├── 2ech3-3ech3.diff
├── 2ech4-3ech4.diff
├── 2ech5-3ech5.diff
├── 2ech6-3ech6.diff
├── 2ech8-3ech8.diff
└── 2ech9-3ech9.diff
├── img
├── 0-0.jpg
├── 1-0.jpg
├── 10-0.jpg
├── 11-1.svg
├── 11-2.png
├── 12-0.jpg
├── 12-1.svg
├── 13-0.jpg
├── 14-0.jpg
├── 14-1.svg
├── 14-2.svg
├── 14-3.svg
├── 14-4.svg
├── 15-0.jpg
├── 16-0.jpg
├── 16-1.png
├── 16-2.svg
├── 17-0.jpg
├── 17-1.png
├── 17-2.svg
├── 17-3.svg
├── 17-4.png
├── 17-5.png
├── 18-0.jpg
├── 19-0.jpg
├── 19-1.png
├── 19-2.svg
├── 19-3.svg
├── 2-0.jpg
├── 2-1.png
├── 2-2.svg
├── 2-3.svg
├── 2-4.svg
├── 2-5.svg
├── 20-0.jpg
├── 21-0.jpg
├── 21-1.png
├── 3-0.jpg
├── 4-0.jpg
├── 4-1.svg
├── 4-2.jpg
├── 4-3.svg
├── 5-0.jpg
├── 5-1.png
├── 6-0.jpg
├── 6-1.svg
├── 7-0.jpg
├── 7-1.png
├── 8-0.jpg
├── 9-0.jpg
├── 9-1.svg
├── 9-2.svg
├── 9-3.svg
└── qr_alipay.png
├── index.html
├── styles
└── ebook.css
└── update.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | _book
2 | Thumbs.db
3 |
--------------------------------------------------------------------------------
/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/.nojekyll
--------------------------------------------------------------------------------
/0.md:
--------------------------------------------------------------------------------
1 | # 零、前言
2 |
3 | > 原文:[Introduction](https://eloquentjavascript.net/00_intro.html)
4 | >
5 | > 译者:[飞龙](https://github.com/wizardforcel)
6 | >
7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
8 | >
9 | > 自豪地采用[谷歌翻译](https://translate.google.cn/)
10 | >
11 | > 部分参考了[《JavaScript 编程精解(第 2 版)》](https://book.douban.com/subject/26707144/)
12 |
13 | > We think we are creating the system for our own purposes. We believe we are making it in our own image... But the computer is not really like us. It is a projection of a very slim part of ourselves: that portion devoted to logic, order, rule, and clarity.
14 |
15 | > Ellen Ullman,《Close to the Machine: Technophilia and its Discontents》
16 |
17 | 
18 |
19 | 这是一本关于指导电脑的书。时至今日,计算机就像螺丝刀一样随处可见,但相比于螺丝刀而言,计算机更复杂一些,并且,让他们做你想让他们做的事情,并不总是那么容易。
20 |
21 | 如果你让计算机执行的任务是常见的,易于理解的任务,例如向你显示你的电子邮件,或像计算器一样工作,则可以打开相应的应用并开始工作。 但对于独特的或开放式的任务,应用可能不存在。
22 |
23 |
24 | 这就是编程可能出现的地方。编程是构建一个程序的行为 - 它是一组精确的指令,告诉计算机做什么。 由于计算机是愚蠢的,迂腐的野兽,编程从根本上是乏味和令人沮丧的。
25 |
26 | 幸运的是,如果你可以克服这个事实,并且甚至可以享受愚蠢机器可以处理的严谨思维,那么编程可以是非常有益的。 它可以让你在几秒钟内完成手动操作。 这是一种方法,让你的电脑工具去做它以前做不到的事情。 它也提供了抽象思维的优秀练习。
27 |
28 | 大多数编程都是用编程语言完成的。 编程语言是一种人工构建的语言,用于指导计算机。 有趣的是,我们发现与电脑沟通的最有效的方式,与我们彼此沟通的方式相差太大。 与人类语言一样,计算机语言可以以新的方式组合词语和词组,从而可以表达新的概念。
29 |
30 | 在某种程度上,基于语言的界面,例如 80 年代和 90 年代的 BASIC 和 DOS 提示符,是与计算机交互的主要方法。 这些已经在很大程度上被视觉界面取代,这些视觉界面更容易学习,但提供更少的自由。 计算机语言仍然存在,如果你知道在哪里看到。 每种现代 Web 浏览器都内置了一种这样的语言,即 JavaScript,因此几乎可以在所有设备上使用。
31 |
32 | 本书将试图让你足够了解这门语言,从而完成有用和有趣的东西。
33 |
34 | ## 关于程序设计
35 |
36 | 除了讲解 JavaScript 之外,本书也会介绍一些程序设计的基本原则。程序设计还是比较复杂的。编程的基本规则简单清晰,但在这些基本规则之上构建的程序却容易变得复杂,导致程序产生了自己的规则和复杂性。即便程序是按照你自己的思路去构建的,你也有可能迷失在代码之间。
37 |
38 | 在阅读本书时,你有可能会觉得书中的概念难以理解。如果你刚刚开始学习编程,那么你估计还有不少东西需要掌握呢。如果你想将所学知识融会贯通,那么就需要去多参考和学习一些资料。
39 |
40 | 是否付出必要的努力完全取决于你自己。当你阅读本书的时候发现任何难点,千万不要轻易就对自己的能力下结论。只要能坚持下去,你就是好样的。稍做休息,复习一下所学的知识点,始终确保自己阅读并理解了示例程序和相关的练习。学习是一项艰巨的任务,但你掌握的所有知识都属于你自己,而且今后的学习道路会愈加轻松。
41 |
42 | > 当行动无利可图时,就收集信息;当信息无利可图时,就休息。
43 |
44 | > Ursula K. Le Guin,《The Left Hand of Darkness》
45 |
46 | 一个程序有很多含义:它是开发人员编写的一段文本、计算机执行的一段指令集合、计算机内存当中的数据以及控制内存中数据的操作集合。我们通常很难将程序与我们日常生活中熟悉的事物进行对比。有一种表面上比较恰当的比喻,即将程序视作包含许多组件的机器,为了让机器正常工作,这些组件通过内部通信来实现整个机器的正常运转。
47 |
48 | 计算机是一台物理机器,充当这些非物质机器的载体。计算机本身并不能实现多么复杂的功能,但计算机之所以有用是因为它们的运算速度非常快。而程序的作用就是将这些看似简单的动作组合起来,然后实现复杂的功能。
49 |
50 | 程序是思想的结晶。编写程序不需要什么物质投入,它很轻量级,通过我们的双手创造。
51 |
52 | 但如果不稍加注意,程序的体积和复杂度就会失去控制,甚至代码的编写者也会感到迷惑。在可控的范围内编写程序是编程过程中首要解决的问题。当程序运行时,一切都是那么美好。编程的精粹就在于如何更好地控制复杂度。质量高的程序的复杂度都不会太高。
53 |
54 | 很多开发人员认为,控制程序复杂度的最好方法就是避免使用不熟悉的技术。他们制定了严格的规则(“最佳实践”),并小心翼翼地呆在他们安全区内。
55 |
56 | 这不仅无聊,而且也是无效的。新问题往往需要新的解决方案。编程领域还很年轻,仍然在迅速发展,并且多样到足以为各种不同的方法留出空间。在程序设计中有许多可怕的错误,你应该继续犯错,以便你能理解它们。好的程序看起来是什么样的感觉,是在实践中发展的,而不是从一系列规则中学到的。
57 |
58 | ## 为什么编程语言重要
59 |
60 | 在计算技术发展伊始,并没有编程语言这个概念。程序看起来就像这样:
61 |
62 | ```
63 | 00110001 00000000 00000000
64 | 00110001 00000001 00000001
65 | 00110011 00000001 00000010
66 | 01010001 00001011 00000010
67 | 00100010 00000010 00001000
68 | 01000011 00000001 00000000
69 | 01000001 00000001 00000001
70 | 00010000 00000010 00000000
71 | 01100010 00000000 00000000
72 | ```
73 |
74 | 该程序计算数字 1~10 之和,并打印出结果:`1+2+...+10=55`。该程序可以运行在一个简单的机器上。在早期计算机上编程时,我们需要在正确的位置设置大量开关阵列,或在纸带上穿孔并将纸带输入计算机中。你可以想象这个过程是多么冗长乏味且易于出错。即便是编写非常简单的程序,也需要有经验的人耗费很大精力才能完成。编写复杂的程序则更是难上加难。
75 |
76 | 当然了,手动输入这些晦涩难懂的位序列(1 和 0)来编写程序的确能让程序员感到很有成就感,而且能给你的职业带来极大的满足感。
77 |
78 | 在上面的程序中,每行都包含一条指令。我们可以用中文来描述这些指令:
79 |
80 | 1. 将数字 0 存储在内存地址中的位置 0。
81 |
82 | 2. 将数字 1 存储在内存地址的位置 1。
83 |
84 | 3. 将内存地址的位置 1 中的值存储在内存地址的位置 2。
85 |
86 | 4. 将内存地址的位置 2 中的值减去数字 11。
87 |
88 | 5. 如果内存地址的位置 2 中的值是 0,则跳转到指令 9。
89 |
90 | 6. 将内存地址的位置 1 中的值加到内存地址的位置 0。
91 |
92 | 7. 将内存地址的位置 1 中的值加上数字 1。
93 |
94 | 8. 跳转到指令 3。
95 |
96 | 9. 输出内存地址的位置 0 中的值。
97 |
98 | 虽说这已经比一大堆位序列要好读了许多,但仍然不清晰。使用名称而不是数字用于指令和存储位置有所帮助:
99 |
100 | ```
101 | Set “total” to 0.
102 | Set “count” to 1.
103 | [loop]
104 | Set “compare” to “count”.
105 | Subtract 11 from “compare”.
106 | If “compare” is zero, continue at [end].
107 | Add “count” to “total”.
108 | Add 1 to “count”.
109 | Continue at [loop].
110 | [end]
111 | Output “total”.
112 | ```
113 |
114 | 现在你能看出该程序是如何工作的吗?前两行代码初始化两个内存位置的值:`total`用于保存累加计算结果,而`count`则用于记录当前数字。你可能觉得`compare`的那行代码看起来有些奇怪。程序想根据`count`是否等于 11 来决定是否应该停止运行。因为我们的机器相当原始,所以只能测试一个数字是否为 0,并根据它做出决策。因此程序用名为`compare`的内存位置存放`count–11`的值,并根据该值是否为 0 决定是否跳转。接下来两行将`count`的值累加到结果上,并将`count`加 1,直到`count`等于`11`为止。
115 |
116 | 下面使用 JavaScript 重新编写了上面的程序:
117 |
118 | ```js
119 | let total = 0, count = 1;
120 | while (count <= 10) {
121 | total += count;
122 | count += 1;
123 | }
124 | console.log(total);
125 | // → 55
126 | ```
127 |
128 | 这个版本的程序得到了一些改进。更为重要的是,我们再也不需要指定程序如何来回跳转了,而是由`while`结构负责完成这个任务。只要我们给予的条件成立,`while`语句就会不停地执行其下方的语句块(包裹在大括号中)。而我们给予的条件是`count<=10`,意思是“`count`小于等于 10”。我们再也不需要创建临时的值并将其与 0 比较,那样的代码十分烦琐。编程语言的一项职责就是,能够帮助我们处理这些烦琐无趣的逻辑。
129 |
130 | 在程序的结尾,也就是`while`语句结束后,我们使用`console.log`操作来输出结果。
131 |
132 | 最后,我们恰好有`range`和`sum`这类方便的操作。下面代码中的`range`函数用于创建数字集合,`sum`函数用于计算数字集合之和:
133 |
134 | ```js
135 | console.log(sum(range(1, 10)));
136 | // → 55
137 | ```
138 |
139 | 我们可以从这里了解到,同一个程序的长度可长可短,可读性可高可低。第一个版本的程序晦涩难懂,而最后一个版本的程序则接近于人类语言的表达方式:将 1~10 范围内的数字之和记录下来(我们会在后面的章节中详细介绍如何编写`sum`和`range`这样的函数)。
140 |
141 | 优秀的编程语言可以为开发人员提供更高层次的抽象,使用类似于人类语言的方式来与计算机进行交互。它有助于省略细节,提供便捷的积木(比如`while`和`console.log`),允许你定义自己的积木(比如`sum`和`range`函数),并使这些积木易于编写。。
142 |
143 | ## 什么是 JavaScript
144 |
145 | JavaScript 诞生于 1995 年。起初,Netscape Navigator 浏览器将其运用在网页上添加程序。自此以后,各类主流图形网页浏览器均采用了 JavaScript。JavaScript 使得现代网页应用程序成为可能 —— 使用 JavaScript 可以直接与用户交互,从而避免每一个动作都需要重新载入页面。但有许多传统网站也会使用 JavaScript 来提供实时交互以及更加智能的表单功能。
146 |
147 | JavaScript 其实和名为Java的程序设计语言没有任何关系。起了这么一个相似的名字完全是市场考虑使然,这并非是一个明智的决定。当 JavaScript 出现时,Java 语言已在市场上得到大力推广且拥有了极高人气,因此某些人觉得依附于 Java 的成功是个不错的主意。而我们现在已经无法摆脱这个名字了。
148 |
149 | 在 JavaScript 被广泛采用之后,ECMA 国际制订了一份标准文档来描述 JavaScript 的工作行为,以便所有声称支持 JavaScript 的软件都使用同一种语言。标准化完成后,该标准被称为 ECMAScript 标准。实际上,术语 ECMAScript 和 JavaScript 可以交换使用。它们不过是同一种语言的两个名字而已。
150 |
151 | 许多人会说 JavaScript 语言的坏话。这其中有很多这样的言论都是正确的。当被要求第一次使用 JavaScript 编写代码时,我当时就觉得这门语言难以驾驭。JavaScript 接受我输入的任何代码,但是又使用和我的想法完全不同的方式来解释代码。由于我没有任何线索知道我之前做了什么,因此我需要做出更多工作,但这也就存在一个实际问题:我们可以自由使用 JavaScript,而这种自由却几乎没有限度。这种设计其实是希望初学者更容易使用 JavaScript 编写程序。但实际上,系统不会指出我们错在何处,因此从程序中找出问题变得更加棘手。
152 |
153 | 但这种自由性也有其优势,许多技术在更为严格的语言中不可能实现,而在 JavaScript 中则留下了实现的余地,正如你看到的那样(比如第十章),有些优势可以弥补 JavaScript 的一些缺点。在正确地学习 JavaScript 并使用它工作了一段时间后,我真正喜欢上了 JavaScript。
154 |
155 | JavaScript 版本众多。大约在 2000~2010 年间,这正是 JavaScript 飞速发展的时期,浏览器支持最多的是 ECMAScript 3。在此期间,ECMA 着手制定 ECMAScript 4,这是一个雄心勃勃的版本,ECMA 计划在这个版本中加入许多彻底的改进与扩展。但由于 ECMAScript 3 被广泛使用,这种过于激进的修改必然会遭遇重重阻碍,最后 ECMA 不得不于 2008 年放弃了版本 4 的制定。这就产生了不那么雄心勃勃的版本 5,这只是一些没有争议的改进,出现在 2009 年。 然后版本 6 在 2015 年诞生,这是一个重大的更新,其中包括计划用于版本 4 的一些想法。从那以后,每年都会有新的更新。
156 |
157 | 语言不断发展的事实意味着,浏览器必须不断跟上,如果你使用的是较老的浏览器,它可能不支持每个特性。 语言设计师会注意,不要做任何可能破坏现有程序的改变,所以新的浏览器仍然可以运行旧的程序。 在本书中,我使用的是 2017 版的 JavaScript。
158 |
159 | Web 浏览器并不是唯一一个可以运行 JavaScript 的平台。有些数据库,比如 MongoDB 和 CouchDB,也使用 JavaScript 作为脚本语言和查询语言。一些桌面和服务器开发的平台,特别是 Node.js 项目(第二十章介绍),为浏览器以外的 JavaScript 编程提供了一个环境。
160 |
161 | ## 代码及相关工作
162 |
163 | 代码是程序的文本内容。本书多数章节都介绍了大量代码。我相信阅读代码和编写代码是学习编程不可或缺的部分。尝试不要仅仅看一眼示例,而应该认真阅读并理解每个示例。刚开始使用这种方式可能会速度较慢并为代码所困惑,但我坚信你很快就可以熟能生巧。对待习题的方法也应该一样。除非你确实已经编写代码解决了问题,否则不要假设你已经理解了问题。
164 |
165 | 建议读者应尝试在实际的 JavaScript 解释器中执行习题代码。这样一来,你就可以马上获知代码工作情况的反馈,而且我希望读者去做更多的试验,而不仅仅局限于习题的要求。
166 |
167 | 可以在 中查阅本书的在线版本,并运行和实验本书中的代码。也可以在在线版本中点击任何代码示例来编辑、运行并查看其产生的输出。在做习题时,你可以访问 ,该网址会提供每个习题的初始代码,让你专心于解答习题。
168 |
169 | 如果想要在本书提供的沙箱以外执行本书代码,需要稍加注意。许多的示例是独立的,而且可以在任何 JavaScript 环境下运行。但后续章节的代码大多数都是为特定环境(浏览器或者 Node.js)编写的,而且只能在这些特定环境下执行代码。此外,许多章节定义了更大的程序,这些章节中出现的代码片段会互相依赖或是依赖于一些外部文件。本书网站的沙箱提供了 zip 压缩文件的链接,该文件包含了所有运行特定章节代码所需的脚本和数据文件。
170 |
171 | ## 本书概览
172 |
173 | 本书包括三个部分。前十二章讨论 JavaScript 语言本身的一些特性。接下来的 8 章讨论网页浏览器和 JavaScript 在网页编程中的实践。最后两章专门讲解另一个使用 JavaScript 编程的环境 —— Node.js。
174 |
175 | 纵观本书,共有 5 个项目实战章,用于讲解规模较大的示例程序,你可以通过这些章来仔细品味真实的编程过程。根据项目出现次序,我们会陆续构建递送机器人(7)、程序设计语言(12)、平台游戏(16)、像素绘图程序(19)和一个动态网站(21)。
176 |
177 | 本书介绍编程语言时,首先使用4章来介绍 JavaScript 语言的基本结构,包括第二章控制结构(比如在本前言中看到的`while`单词)、第三章函数(编写你自己的积木)和第四章数据结构。此后你就可以编写简单的程序了。接下来,第五章和第六章介绍函数和对象的运用技术,以编写更加抽象的代码并以此来控制复杂度。
178 |
179 | 介绍完第一个项目实战(7)之后,将会继续讲解语言部分,例如第八章错误处理和 bug 修复、第九章正则表达式(处理文本数据的重要工具)、第十章模块化(解决复杂度的问题)以及第十一章异步编程(处理需要时间的事件)。第二个项目实战章节(12)则是对本书第一部分的总结。
180 |
181 | 第二部分(第十三章到第十九章),阐述了浏览器 JavaScript 中的一些工具。你将会学到在屏幕上显示某些元素的方法(第十四章与第十七章),响应用户输入的方法(第十五章)和通过网络通信的方法(第十八章)。这部分又有两个项目实战章节。
182 |
183 | 此后,第二十章阐述 Node.js,而第二十一章使用该工具构建一个简单的网页系统。
184 |
185 | ## 本书版式约定
186 |
187 | 本书中存在大量代码,程序(包括你迄今为止看到的一些示例)代码的字体如下所示:
188 |
189 | ```js
190 | function factorial(n) {
191 | if (n == 0) {
192 | return 1;
193 | } else {
194 | return factorial(n - 1) * n;
195 | }
196 | }
197 | ```
198 |
199 | 为了展示程序产生的输出,本书常在代码后编写代码期望输出,输出结果前会加上两个反斜杠和一个箭头。
200 |
201 | ```js
202 | console.log(factorial(8));
203 | // → 40320
204 | ```
205 |
206 | 祝好运!
207 |
--------------------------------------------------------------------------------
/1.md:
--------------------------------------------------------------------------------
1 | ## 一、值,类型和运算符
2 |
3 | > 原文:[Values, Types, and Operators](http://eloquentjavascript.net/01_values.html)
4 | >
5 | > 译者:[飞龙](https://github.com/wizardforcel)
6 | >
7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
8 | >
9 | > 自豪地采用[谷歌翻译](https://translate.google.cn/)
10 | >
11 | > 部分参考了[《JavaScript 编程精解(第 2 版)》](https://book.douban.com/subject/26707144/)
12 |
13 | > 在机器的表面之下,程序在运转。 它不费力就可以扩大和缩小。 在和谐的关系中,电子散开并重新聚合。 监视器上的表格只是水面上的涟漪。 本质隐藏在下面。
14 | >
15 | > Master Yuan-Ma,《The Book of Programming》
16 |
17 | 
18 |
19 | 计算机世界里只有数据。 你可以读取数据,修改数据,创建新数据 - 但不能提及不是数据的东西。 所有这些数据都以位的长序列存储,因此基本相似。
20 |
21 | 位是任何类型的二值的东西,通常描述为零和一。 在计算机内部,他们有一些形式,例如高电荷或低电荷,强信号或弱信号,或 CD 表面上的亮斑点或暗斑点。 任何一段离散信息都可以简化为零和一的序列,从而以位表示。
22 |
23 | 例如,我们可以用位来表示数字 13。 它的原理与十进制数字相同,但不是 10 个不同的数字,而只有 2 个,每个数字的权重从右到左增加 2 倍。 以下是组成数字 13 的位,下方显示数字的权重:
24 |
25 | ```
26 | 0 0 0 0 1 1 0 1
27 | 128 64 32 16 8 4 2 1
28 | ```
29 |
30 | 因此,这就是二进制数`00001101`,或者`8+4+1`,即 13。
31 |
32 | ## 值
33 |
34 | 想象一下位之海 - 一片它们的海洋。 典型的现代计算机的易失性数据存储器(工作存储器)中,有超过 300 亿位。非易失性存储(硬盘或等价物)往往还有几个数量级。
35 |
36 | 为了能够在不丢失的情况下,处理这些数量的数据,我们必须将它们分成代表信息片段的块。 在 JavaScript 环境中,这些块称为值。 虽然所有值都是由位构成的,但他们起到不同的作用,每个值都有一个决定其作用的类型。 有些值是数字,有些值是文本片段,有些值是函数,等等。
37 |
38 | 要创建一个值,你只需要调用它的名字。 这很方便。 你不必为你的值收集建筑材料或为其付费。 你只需要调用它,然后刷的一下,你就有了它。 当然,它们并不是真正凭空创造的。 每个值都必须存储在某个地方,如果你想同时使用大量的值,则可能会耗尽内存。 幸运的是,只有同时需要它们时,这才是一个问题。 只要你不再使用值,它就会消失,留下它的一部分作为下一代值的建筑材料。
39 |
40 | 本章将会介绍 JavaScript 程序当中的基本元素,包括简单的值类型以及值运算符。
41 |
42 | ## 数字
43 |
44 | 数字(`Number`)类型的值即数字值。在 JavaScript 中写成如下形式:
45 |
46 | ```js
47 | 13
48 | ```
49 |
50 | 在程序中使用这个值的时候,就会将数字 13 以位序列的方式存放在计算机的内存当中。
51 |
52 | JavaScript使用固定数量的位(64 位)来存储单个数字值。 你可以用 64 位创造很多模式,这意味着可以表示的不同数值是有限的。 对于`N`个十进制数字,可以表示的数值数量是`10^N`。 与之类似,给定 64 个二进制数字,你可以表示`2^64`个不同的数字,大约 18 亿亿(18 后面有 18 个零)。太多了。
53 |
54 | 过去计算机内存很小,人们倾向于使用一组 8 位或 16 位来表示他们的数字。 这么小的数字很容易意外地溢出,最终得到的数字不能放在给定的位数中。 今天,即使是装在口袋里的电脑也有足够的内存,所以你可以自由使用 64 位的块,只有在处理真正的天文数字时才需要担心溢出。
55 |
56 | 不过,并非所有 18 亿亿以下的整数都能放在 JavaScript 数值中。 这些位也存储负数,所以一位用于表示数字的符号。 一个更大的问题是,也必须表示非整数。 为此,一些位用于存储小数点的位置。 可以存储的实际最大整数更多地在 9000 万亿(15 个零)的范围内 - 这仍然相当多。
57 |
58 | 使用小数点来表示分数。
59 |
60 | ```js
61 | 9.81
62 | ```
63 |
64 | 对于非常大或非常小的数字,你也可以通过输入`e`(表示指数),后面跟着指数来使用科学记数法:
65 |
66 | ```js
67 | 2.998e8
68 | ```
69 |
70 | 即`2.998 * 10^8 = 299,800,000`。
71 |
72 | 当计算小于前文当中提到的 9000 万亿的整数时,其计算结果会十分精确,不过在计算小数的时候精度却不高。正如(`pi`)无法使用有限个数的十进制数字表示一样,在使用 64 位来存储分数时也同样会丢失一些精度。虽说如此,但这类丢失精度只会在一些特殊情况下才会出现问题。因此我们需要注意在处理分数时,将其视为近似值,而非精确值。
73 |
74 | ### 算术
75 |
76 | 与数字密切相关的就是算术。比如,加法或者乘法之类的算术运算会使用两个数值,并产生一个新的数字。JavaScript 中的算术运算如下所示:
77 |
78 | ```js
79 | 100 + 4 * 11
80 | ```
81 |
82 | 我们把`+`和`*`符号称为运算符。第一个符号表示加法,第二个符号表示乘法。将一个运算符放在两个值之间,该运算符将会使用其旁边的两个值产生一个新值。
83 |
84 | 但是这个例子的意思是“将 4 和 100 相加,并将结果乘 11”,还是是在加法之前计算乘法? 正如你可能猜到的那样,乘法首先计算。 但是和数学一样,你可以通过将加法包在圆括号中来改变它:
85 |
86 | ```js
87 | (100 + 4) * 11
88 | ```
89 |
90 | `–`运算符表示减法,`/`运算符则表示除法。
91 |
92 | 在运算符同时出现,并且没有括号的情况下,其运算顺序根据运算符优先级确定。示例中的乘法运算符优先级高于加法。而`/`运算符和`*`运算符优先级相同,`+`运算符和`–`运算符优先级也相同。当多个具有相同优先级的运算符相邻出现时,运算从左向右执行,比如`1–2+1`的运算顺序是`(1–2)+1`。
93 |
94 | 你无需担心这些运算符的优先级规则,不确定的时候只需要添加括号即可。
95 |
96 | 还有一个算术运算符,你可能无法立即认出。 `%`符号用于表示取余操作。 `X % Y`是`Y`除`X`的余数。 例如,`314 % 100`产生`14`,`144 % 12`产生`0`。 余数的优先级与乘法和除法的优先级相同。 你还经常会看到这个运算符被称为模运算符。
97 |
98 | ### 特殊数字
99 |
100 | 在 JavaScript 中有三个特殊的值,它们虽然是数字,但看起来却跟一般的数字不太一样。
101 |
102 | 前两个是`Infinity`和`-Infinity`,它们代表正无穷和负无穷。 “无穷减一”仍然是“无穷”,依此类推。 尽管如此,不要过分信任基于无穷大的计算。 它在数学上不合理,并且很快导致我们的下一个特殊数字:`NaN`。
103 |
104 | `NaN`代表“不是数字”,即使它是数字类型的值。 例如,当你尝试计算`0/0`(零除零),`Infinity - Infinity`或任何其他数字操作,它不会产生有意义的结果时,你将得到此结果。
105 |
106 | ## 字符串
107 |
108 | 下一个基本数据类型是字符串(`String`)。 字符串用于表示文本。 它们是用引号括起来的:
109 |
110 | ```js
111 | `Down on the sea`
112 | "Lie on the ocean"
113 | 'Float on the ocean'
114 | ```
115 |
116 | 只要字符串开头和结尾的引号匹配,就可以使用单引号,双引号或反引号来标记字符串。
117 |
118 | 几乎所有的东西都可以放在引号之间,并且 JavaScript 会从中提取字符串值。 但少数字符更难。 你可能难以想象,如何在引号之间加引号。 当使用反引号(`` ` ``)引用字符串时,换行符(当你按回车键时获得的字符)可能会被包含,而无需转义。
119 |
120 | 若要将这些字符存入字符串,需要使用下列规则:当反斜杠(`\`)出现在引号之间的文本中时,表示紧跟在其后的字符具有特殊含义,我们将其称之为转义符。当引号紧跟在反斜杠后时,并不意味着字符串结束,而表示这个引号是字符串的一部分。当字符`n`出现在反斜杠后时,JavaScript 将其解释成换行符。以此类推,`\t`表示制表符,我们来看看下面这个字符串:
121 |
122 | ```js
123 | "This is the first line\nAnd this is the second"
124 | ```
125 |
126 | 该字符串实际表示的文本是:
127 |
128 | ```
129 | This is the first line
130 | And this is the second
131 | ```
132 |
133 | 当然,在某些情况下,你希望字符串中的反斜杠只是反斜杠,而不是特殊代码。 如果两个反斜杠写在一起,它们将合并,并且只有一个将留在结果字符串值中。 这就是字符串“`A newline character is written like "\n".`”的表示方式:
134 |
135 | ```js
136 | "A newline character is written like \"\\n\"."
137 | ```
138 |
139 | 字符串也必须建模为一系列位,以便能够存在于计算机内部。 JavaScript 执行此操作的方式基于 Unicode 标准。 该标准为你几乎需要的每个字符分配一个数字,包括来自希腊语,阿拉伯语,日语,亚美尼亚语,以及其他的字符。 如果我们为每个字符分配一个数字,则可以用一系列数字来描述一个字符串。
140 |
141 | 这就是 JavaScript 所做的。 但是有一个复杂的问题:JavaScript 的表示为每个字符串元素使用 16 位,它可以描述多达 2 的 16 次方个不同的字符。 但是,Unicode 定义的字符多于此 - 大约是此处的两倍。 所以有些字符,比如许多 emoji,在 JavaScript 字符串中占据了两个“字符位置”。 我们将在第 5 章中回来讨论。
142 |
143 | 我们不能将除法,乘法或减法运算符用于字符串,但是`+`运算符却可以。这种情况下,运算符并不表示加法,而是连接操作:将两个字符串连接到一起。以下语句可以产生字符串`"concatenate"`:
144 |
145 | ```js
146 | "con" + "cat" + "e" + "nate"
147 | ```
148 |
149 | 字符串值有许多相关的函数(方法),可用于对它们执行其他操作。 我们将在第 4 章中回来讨论。
150 |
151 | 用单引号或双引号编写的字符串的行为非常相似 - 唯一的区别是需要在其中转义哪种类型的引号。 反引号字符串,通常称为模板字面值,可以实现更多的技巧。 除了能够跨越行之外,它们还可以嵌入其他值。
152 |
153 | ```js
154 | `half of 100 is ${100 / 2}`
155 | ```
156 |
157 | 当你在模板字面值中的`$ {}`中写入内容时,将计算其结果,转换为字符串并包含在该位置。 这个例子产生`"half of 100 is 50"`。
158 |
159 | ## 一元运算符
160 |
161 | 并非所有的运算符都是用符号来表示,还有一些运算符是用单词表示的。比如`typeof`运算符,会产生一个字符串的值,内容是给定值的具体类型。
162 |
163 | ```js
164 | console.log(typeof 4.5)
165 | // → number
166 | console.log(typeof "x")
167 | // → string
168 | ```
169 |
170 | 我们将在示例代码中使用`console.log`,来表示我们希望看到求值结果。更多内容请见下一章。
171 |
172 | 我们所见过的绝大多数运算符都使用两个值进行操作,而`typeof`仅接受一个值进行操作。使用两个值的运算符称为二元运算符,而使用一个值的则称为一元运算符。减号运算符既可用作一元运算符,也可用作二元运算符。
173 |
174 | ```js
175 | console.log(- (10 - 2))
176 | // → -8
177 | ```
178 |
179 | ## 布尔值
180 |
181 | 拥有一个值,它能区分两种可能性,通常是有用的,例如“是”和“否”或“开”和“关”。 为此,JavaScript 拥有布尔(`Boolean`)类型,它有两个值:`true`和`false`,它们就写成这些单词。
182 |
183 | ### 比较
184 |
185 | 一种产生布尔值的方法如下所示:
186 |
187 | ```js
188 | console.log(3 > 2)
189 | // → true
190 | console.log(3 < 2)
191 | // → false
192 | ```
193 |
194 | `>`和`<`符号分别表示“大于”和“小于”。这两个符号是二元运算符,通过该运算符返回的结果是一个布尔值,表示其运算是否为真。
195 |
196 | 我们可以使用相同的方法比较字符串。
197 |
198 | ```js
199 | console.log("Aardvark" < "Zoroaster")
200 | // → true
201 | ```
202 |
203 | 字符串排序的方式大致是字典序,但不真正是你期望从字典中看到的那样:大写字母总是比小写字母“小”,所以`"Z"<"a"`,非字母字符(`!`,`-`等)也包含在排序中。 比较字符串时,JavaScript 从左向右遍历字符,逐个比较 Unicode 代码。
204 |
205 | 其他类似的运算符则包括`>=`(大于等于),`<=`(小于等于),`==`(等于)和`!=`(不等于)。
206 |
207 | ```js
208 | console.log("Apple" == "Orange")
209 | // → false
210 | ```
211 |
212 | 在 JavaScript 中,只有一个值不等于其自身,那就是`NaN`(Not a Number,非数值)。
213 |
214 | ```js
215 | console.log(NaN == NaN)
216 | // → false
217 | ```
218 |
219 | `NaN`用于表示非法运算的结果,正因如此,不同的非法运算结果也不会相等。
220 |
221 | ### 逻辑运算符
222 |
223 | 还有一些运算符可以应用于布尔值上。JavaScript 支持三种逻辑运算符:与(and),或(or)和非(not)。这些运算符可以用于推理布尔值。
224 |
225 | `&&`运算符表示逻辑与,该运算符是二元运算符,只有当赋给它的两个值均为`true`时其结果才是真。
226 |
227 | ```js
228 | console.log(true && false)
229 | // → false
230 | console.log(true && true)
231 | // → true
232 | ```
233 |
234 | `||`运算符表示逻辑或。当两个值中任意一个为`true`时,结果就为真。
235 |
236 | ```js
237 | console.log(false || true)
238 | // → true
239 | console.log(false || false)
240 | // → false
241 | ```
242 |
243 | 感叹号(`!`)表示逻辑非,该运算符是一元运算符,用于反转给定的值,比如`!true`的结果是`false`,而`!false`结果是`true`。
244 |
245 | 在混合使用布尔运算符和其他运算符的情况下,总是很难确定什么时候需要使用括号。实际上,只要熟悉了目前为止我们介绍的运算符,这个问题就不难解决了。`||`优先级最低,其次是`&&`,接着是比较运算符(`>`,`==`等),最后是其他运算符。基于这些优先级顺序,我们在一般情况下最好还是尽量少用括号,比如说:
246 |
247 | ```js
248 | 1 + 1 == 2 && 10 * 10 > 50
249 | ```
250 |
251 | 现在我们来讨论最后一个逻辑运算符,它既不属于一元运算符,也不属于二元运算符,而是三元运算符(同时操作三个值)。该运算符由一个问号和冒号组成,如下所示。
252 |
253 | ```js
254 | console.log(true ? 1 : 2);
255 | // → 1
256 | console.log(false ? 1 : 2);
257 | // → 2
258 | ```
259 |
260 | 这个被称为条件运算符(或者有时候只是三元运算符,因为它是该语言中唯一的这样的运算符)。 问号左侧的值“挑选”另外两个值中的一个。 当它为真,它选择中间的值,当它为假,则是右边的值。
261 |
262 | ## 空值
263 |
264 | 有两个特殊值,写成`null`和`undefined`,用于表示不存在有意义的值。 它们本身就是值,但它们没有任何信息。
265 |
266 | 在 JavaScript 语言中,有许多操作都会产生无意义的值(我们会在后面的内容中看到实例),这些操作会得到`undefined`的结果仅仅只是因为每个操作都必须产生一个值。
267 |
268 | `undefined`和`null`之间的意义差异是 JavaScript 设计的一个意外,大多数时候它并不重要。 在你实际上不得不关注这些值的情况下,我建议将它们视为几乎可互换的。
269 |
270 | ## 自动类型转换
271 |
272 | 在引言中,我提到 JavaScript 会尽可能接受几乎所有你给他的程序,甚至是那些做些奇怪事情的程序。 以下表达式很好地证明了这一点:
273 |
274 | ```js
275 | console.log(8 * null)
276 | // → 0
277 | console.log("5" - 1)
278 | // → 4
279 | console.log("5" + 1)
280 | // → 51
281 | console.log("five" * 2)
282 | // → NaN
283 | console.log(false == 0)
284 | // → true
285 | ```
286 |
287 | 当运算符应用于类型“错误”的值时,JavaScript 会悄悄地将该值转换为所需的类型,并使用一组通常不是你想要或期望的规则。 这称为类型转换。 第一个表达式中的`null`变为`0`,第二个表达式中的`"5"`变为`5`(从字符串到数字)。 然而在第三个表达式中,`+`在数字加法之前尝试字符串连接,所以`1`被转换为`"1"`(从数字到字符串)。
288 |
289 | 当某些不能明显映射为数字的东西(如`"five"`或`undefined`)转换为数字时,你会得到值`NaN`。 `NaN`进一步的算术运算会产生`NaN`,所以如果你发现自己在一个意想不到的地方得到了它,需要寻找意外的类型转换。
290 |
291 | 当相同类型的值之间使用`==`符号进行比较时,其运算结果很好预测:除了`NaN`这种情况,只要两个值相同,则返回`true`。但如果类型不同,JavaScript 则会使用一套复杂难懂的规则来确定输出结果。在绝大多数情况下,JavaScript 只是将其中一个值转换成另一个值的类型。但如果运算符两侧存在`null`或`undefined`,那么只有两侧均为`null`或`undefined`时结果才为`true`。
292 |
293 | ```js
294 | console.log(null == undefined);
295 | // → true
296 | console.log(null == 0);
297 | // → false
298 | ```
299 |
300 | 这种行为通常很有用。 当你想测试一个值是否具有真值而不是`null`或`undefined`时,你可以用`==`(或`!=`)运算符将它与`null`进行比较。
301 |
302 | 但是如果你想测试某些东西是否严格为“false”呢? 字符串和数字转换为布尔值的规则表明,`0`,`NaN`和空字符串(`""`)计为`false`,而其他所有值都计为`true`。 因此,像`'0 == false'`和`"" == false`这样的表达式也是真的。 当你不希望发生自动类型转换时,还有两个额外的运算符:`===`和`!==`。 第一个测试是否严格等于另一个值,第二个测试它是否不严格相等。 所以`"" === false`如预期那样是错误的。
303 |
304 | 我建议使用三字符比较运算符来防止意外类型转换的发生,避免作茧自缚。但如果比较运算符两侧的值类型是相同的,那么使用较短的运算符也没有问题。
305 |
306 | ### 逻辑运算符的短路特性
307 |
308 | 逻辑运算符`&&`和`||`以一种特殊的方式处理不同类型的值。 他们会将其左侧的值转换为布尔型,来决定要做什么,但根据运算符和转换结果,它们将返回原始的左侧值或右侧值。
309 |
310 | 例如,当左侧值可以转换为`true`时,`||`运算符会返回它,否则返回右侧值。 当值为布尔值时,这具有预期的效果,并且对其他类型的值做类似的操作。
311 |
312 | ```js
313 | console.log(null || "user")
314 | // → user
315 | console.log("Agnes" || "user")
316 | // → Agnes
317 | ```
318 |
319 | 我们可以此功能用作回落到默认值的方式。 如果你的一个值可能是空的,你可以把`||`和备选值放在它之后。 如果初始值可以转换为`false`,那么你将得到备选值。
320 |
321 | `&&`运算符工作方式与其相似但不相同。当左侧的值可以被转换成`false`时,`&&`运算符会返回左侧值,否则返回右侧值。
322 |
323 | 这两个运算符的另一个重要特性是,只在必要时求解其右侧的部分。 在`true || X`的情况下,不管`X`是什么 - 即使它是一个执行某些恶意操作的程序片段,结果都是`true`,并且`X`永远不会求值。 `false && X`也是一样,它是`false`的,并且忽略`X`。 这称为短路求值。
324 |
325 | 条件运算符以类似的方式工作。 在第二个和第三个值中,只有被选中的值才会求值。
326 |
327 | ## 本章小结
328 |
329 | 在本章中,我们介绍了 JavaScript 的四种类型的值:数字,字符串,布尔值和未定义值。
330 |
331 | 通过输入值的名称(`true`,`null`)或值(`13`,`"abc"`)就可以创建它们。你还可以通过运算符来对值进行合并和转换操作。本章已经介绍了算术二元运算符(`+`,`–`,`*`,`/`和`%`),字符串连接符(`+`),比较运算符(`==`,`!=`,`===`,`!==`,`<`,`>`,`<=`和`>=`),逻辑运算符(`&&`和`||`)和一些一元运算符(`–`表示负数,`!`表示逻辑非,`typeof`用于查询值的类型)。
332 |
333 | 这为你提供了足够的信息,将 JavaScript 用作便携式计算器,但并不多。 下一章将开始将这些表达式绑定到基本程序中。
334 |
--------------------------------------------------------------------------------
/10.md:
--------------------------------------------------------------------------------
1 | # 十、模块
2 |
3 | > 原文:[Modules](http://eloquentjavascript.net/10_modules.html)
4 | >
5 | > 译者:[飞龙](https://github.com/wizardforcel)
6 | >
7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
8 | >
9 | > 自豪地采用[谷歌翻译](https://translate.google.cn/)
10 |
11 | > 编写易于删除,而不是易于扩展的代码。
12 | >
13 | > Tef,《Programming is Terrible》
14 |
15 | 
16 |
17 | 理想的程序拥有清晰的结构。 它的工作方式很容易解释,每个部分都起到明确的作用。
18 |
19 | 典型的真实程序会有机地增长。 新功能随着新需求的出现而增加。 构建和维护结构是额外的工作,只有在下一次有人参与该计划时,才会得到回报。 所以它易于忽视,并让程序的各个部分变得深深地纠缠在一起。
20 |
21 | 这导致了两个实际问题。 首先,这样的系统难以理解。 如果一切都可以接触到一切其它东西,那么很难单独观察任何给定的片段。 你不得不全面理解整个东西。 其次,如果你想在另一个场景中,使用这种程序的任何功能,比起试图从它的上下文中将它分离出来,重写它可能要容易。
22 |
23 | 术语“大泥球”通常用于这种大型,无结构的程序。 一切都粘在一起,当你试图挑选出一段代码时,整个东西就会分崩离析,你的手会变脏。
24 |
25 | ## 模块
26 |
27 | 模块试图避免这些问题。 模块是一个程序片段,规定了它依赖的其他部分,以及它为其他模块提供的功能(它的接口)。
28 |
29 | 模块接口与对象接口有许多共同之处,我们在第 6 章中看到。它们向外部世界提供模块的一部分,并使其余部分保持私有。 通过限制模块彼此交互的方式,系统变得更像积木,其中的组件通过明确定义的连接器进行交互,而不像泥浆一样,一切都混在一起。
30 |
31 | 模块之间的关系称为依赖关系。 当一个模块需要另一个模块的片段时,就说它依赖于这个模块。 当模块中明确规定了这个事实时,它可以用于确定,需要哪些其他模块才能使用给定的模块,并自动加载依赖关系。
32 |
33 | 为了以这种方式分离模块,每个模块需要它自己的私有作用域。
34 |
35 | 将你的 JavaScript 代码放入不同的文件,不能满足这些要求。 这些文件仍然共享相同的全局命名空间。 他们可以有意或无意干扰彼此的绑定。 依赖性结构仍不清楚。 我们将在本章后面看到,我们可以做得更好。
36 |
37 | 合适的模块结构可能难以为程序设计。 在你还在探索这个问题的阶段,尝试不同的事情来看看什么是可行的,你可能不想过多担心它,因为这可能让你分心。 一旦你有一些感觉可靠的东西,现在是后退一步并组织它的好时机。
38 |
39 | ## 包
40 |
41 | 从单独的片段中构建一个程序,并实际上能够独立运行这些片段的一个优点是,你可能能够在不同的程序中应用相同的部分。
42 |
43 | 但如何实现呢? 假设我想在另一个程序中使用第 9 章中的`parseINI`函数。 如果清楚该函数依赖什么(在这种情况下什么都没有),我可以将所有必要的代码复制到我的新项目中并使用它。 但是,如果我在代码中发现错误,我可能会在当时正在使用的任何程序中将其修复,并忘记在其他程序中修复它。
44 |
45 | 一旦你开始复制代码,你很快就会发现,自己在浪费时间和精力来到处复制并使他们保持最新。
46 |
47 | 这就是包的登场时机。包是可分发(复制和安装)的一大块代码。 它可能包含一个或多个模块,并且具有关于它依赖于哪些其他包的信息。 一个包通常还附带说明它做什么的文档,以便那些不编写它的人仍然可以使用它。
48 |
49 | 在包中发现问题或添加新功能时,会将包更新。 现在依赖它的程序(也可能是包)可以升级到新版本。
50 |
51 | 以这种方式工作需要基础设施。 我们需要一个地方来存储和查找包,以及一个便利方式来安装和升级它们。 在 JavaScript 世界中,这个基础结构由 [NPM](https://npmjs.org) 提供。
52 |
53 | NPM 是两个东西:可下载(和上传)包的在线服务,以及可帮助你安装和管理它们的程序(与 Node.js 捆绑在一起)。
54 |
55 | 在撰写本文时,NPM 上有超过 50 万个不同的包。 其中很大一部分是垃圾,我应该提一下,但几乎所有有用的公开包都可以在那里找到。 例如,一个 INI 文件解析器,类似于我们在第 9 章中构建的那个,可以在包名称`ini`下找到。
56 |
57 | 第 20 章将介绍如何使用`npm`命令行程序在局部安装这些包。
58 |
59 | 使优质的包可供下载是非常有价值的。 这意味着我们通常可以避免重新创建一百人之前写过的程序,并在按下几个键时得到一个可靠,充分测试的实现。
60 |
61 | 软件的复制很便宜,所以一旦有人编写它,分发给其他人是一个高效的过程。但首先把它写出来是工作量,回应在代码中发现问题的人,或者想要提出新功能的人,是更大的工作量。
62 |
63 | 默认情况下,你拥有你编写的代码的版权,其他人只有经过你的许可才能使用它。但是因为有些人不错,而且由于发布好的软件可以使你在程序员中出名,所以许多包都会在许可证下发布,明确允许其他人使用它。
64 |
65 | NPM 上的大多数代码都以这种方式授权。某些许可证要求你还要在相同许可证下发布基于那个包构建的代码。其他要求不高,只是要求在分发代码时保留许可证。 JavaScript 社区主要使用后一种许可证。使用其他人的包时,请确保你留意了他们的许可证。
66 |
67 | ## 即兴的模块
68 |
69 | 2015 年之前,JavaScript 语言没有内置的模块系统。 然而,尽管人们已经用 JavaScript 构建了十多年的大型系统,他们需要模块。
70 |
71 | 所以他们在语言之上设计了自己的模块系统。 你可以使用 JavaScript 函数创建局部作用域,并使用对象来表示模块接口。
72 |
73 | 这是一个模块,用于日期名称和数字之间的转换(由`Date`的`getDay`方法返回)。 它的接口由`weekDay.name`和`weekDay.number`组成,它将局部绑定名称隐藏在立即调用的函数表达式的作用域内。
74 |
75 | ```js
76 | const weekDay = function() {
77 | const names = ["Sunday", "Monday", "Tuesday", "Wednesday",
78 | "Thursday", "Friday", "Saturday"];
79 | return {
80 | name(number) { return names[number]; },
81 | number(name) { return names.indexOf(name); }
82 | };
83 | }();
84 |
85 | console.log(weekDay.name(weekDay.number("Sunday")));
86 | // → Sunday
87 | ```
88 |
89 | 这种风格的模块在一定程度上提供了隔离,但它不声明依赖关系。 相反,它只是将其接口放入全局范围,并希望它的依赖关系(如果有的话)也这样做。 很长时间以来,这是 Web 编程中使用的主要方法,但现在它几乎已经过时。
90 |
91 | 如果我们想让依赖关系成为代码的一部分,我们必须控制依赖关系的加载。 实现它需要能够将字符串执行为代码。 JavaScript 可以做到这一点。
92 |
93 | ## 将数据执行为代码
94 |
95 | 有几种方法可以将数据(代码的字符串)作为当前程序的一部分运行。
96 |
97 | 最明显的方法是特殊运算符`eval`,它将在当前作用域内执行一个字符串。 这通常是一个坏主意,因为它破坏了作用域通常拥有的一些属性,比如易于预测给定名称所引用的绑定。
98 |
99 | ```js
100 | const x = 1;
101 | function evalAndReturnX(code) {
102 | eval(code);
103 | return x;
104 | }
105 |
106 | console.log(evalAndReturnX("var x = 2"));
107 | // → 2
108 | console.log(x);
109 | // → 1
110 | ```
111 |
112 | 将数据解释为代码的不太可怕的方法,是使用`Function`构造器。 它有两个参数:一个包含逗号分隔的参数名称列表的字符串,和一个包含函数体的字符串。 它将代码封装在一个函数值中,以便它获得自己的作用域,并且不会对其他作用域做出奇怪的事情。
113 |
114 | ```py
115 | let plusOne = Function("n", "return n + 1;");
116 | console.log(plusOne(4));
117 | // → 5
118 | ```
119 |
120 | 这正是我们需要的模块系统。 我们可以将模块的代码包装在一个函数中,并将该函数的作用域用作模块作用域。
121 |
122 | ## CommonJS
123 |
124 | 用于连接 JavaScript 模块的最广泛的方法称为 CommonJS 模块。 Node.js 使用它,并且是 NPM 上大多数包使用的系统。
125 |
126 | CommonJS 模块的主要概念是称为`require`的函数。 当你使用依赖项的模块名称调用这个函数时,它会确保该模块已加载并返回其接口。
127 |
128 | 由于加载器将模块代码封装在一个函数中,模块自动得到它们自己的局部作用域。 他们所要做的就是,调用`require`来访问它们的依赖关系,并将它们的接口放在绑定到`exports`的对象中。
129 |
130 | 此示例模块提供了日期格式化功能。 它使用 NPM的两个包,`ordinal`用于将数字转换为字符串,如`"1st"`和`"2nd"`,以及`date-names`用于获取星期和月份的英文名称。 它导出函数`formatDate`,它接受一个`Date`对象和一个模板字符串。
131 |
132 | 模板字符串可包含指明格式的代码,如`YYYY`用于全年,`Do`用于每月的序数日。 你可以给它一个像`"MMMM Do YYYY"`这样的字符串,来获得像`"November 22nd 2017"`这样的输出。
133 |
134 | ```js
135 | const ordinal = require("ordinal");
136 | const {days, months} = require("date-names");
137 |
138 | exports.formatDate = function(date, format) {
139 | return format.replace(/YYYY|M(MMM)?|Do?|dddd/g, tag => {
140 | if (tag == "YYYY") return date.getFullYear();
141 | if (tag == "M") return date.getMonth();
142 | if (tag == "MMMM") return months[date.getMonth()];
143 | if (tag == "D") return date.getDate();
144 | if (tag == "Do") return ordinal(date.getDate());
145 | if (tag == "dddd") return days[date.getDay()];
146 | });
147 | };
148 | ```
149 |
150 | `ordinal`的接口是单个函数,而`date-names`导出包含多个东西的对象 - `days`和`months`是名称数组。 为导入的接口创建绑定时,解构是非常方便的。
151 |
152 | 该模块将其接口函数添加到`exports`,以便依赖它的模块可以访问它。 我们可以像这样使用模块:
153 |
154 | ```js
155 | const {formatDate} = require("./format-date");
156 |
157 | console.log(formatDate(new Date(2017, 9, 13),
158 | "dddd the Do"));
159 | // → Friday the 13th
160 | ```
161 |
162 | 我们可以用最简单的形式定义`require`,如下所示:
163 |
164 | ```js
165 | require.cache = Object.create(null);
166 |
167 | function require(name) {
168 | if (!(name in require.cache)) {
169 | let code = readFile(name);
170 | let module = {exports: {}};
171 | require.cache[name] = module;
172 | let wrapper = Function("require, exports, module", code);
173 | wrapper(require, module.exports, module);
174 | }
175 | return require.cache[name].exports;
176 | }
177 | ```
178 |
179 | 在这段代码中,`readFile`是一个构造函数,它读取一个文件并将其内容作为字符串返回。标准的 JavaScript 没有提供这样的功能,但是不同的 JavaScript 环境(如浏览器和 Node.js)提供了自己的访问文件的方式。这个例子只是假设`readFile`存在。
180 |
181 | 为了避免多次加载相同的模块,`require`需要保存(缓存)已经加载的模块。被调用时,它首先检查所请求的模块是否已加载,如果没有,则加载它。这涉及到读取模块的代码,将其包装在一个函数中,然后调用它。
182 |
183 | 我们之前看到的`ordinal`包的接口不是一个对象,而是一个函数。 CommonJS 模块的特点是,尽管模块系统会为你创建一个空的接口对象(绑定到`exports`),但你可以通过覆盖`module.exports`来替换它。许多模块都这么做,以便导出单个值而不是接口对象。
184 |
185 | 通过将`require`,`exports`和`module`定义为生成的包装函数的参数(并在调用它时传递适当的值),加载器确保这些绑定在模块的作用域中可用。
186 |
187 | 提供给`require`的字符串翻译为实际的文件名或网址的方式,在不同系统有所不同。 当它以`"./"`或`"../"`开头时,它通常被解释为相对于当前模块的文件名。 所以`"./format-date"`就是在同一个目录中,名为`format-date.js`的文件。
188 |
189 | 当名称不是相对的时,Node.js 将按照该名称查找已安装的包。 在本章的示例代码中,我们将把这些名称解释为 NPM 包的引用。 我们将在第 20 章详细介绍如何安装和使用 NPM 模块。
190 |
191 | 现在,我们不用编写自己的 INI 文件解析器,而是使用 NPM 中的某个:
192 |
193 | ```js
194 | const {parse} = require("ini");
195 |
196 | console.log(parse("x = 10\ny = 20"));
197 | // → {x: "10", y: "20"}
198 | ```
199 |
200 | ## ECMAScript 模块
201 |
202 | CommonJS 模块很好用,并且与 NPM 一起,使 JavaScript 社区开始大规模共享代码。
203 |
204 | 但他们仍然是个简单粗暴的黑魔法。 例如,表示法有点笨拙 - 添加到`exports`的内容在局部作用域中不可用。 而且因为`require`是一个正常的函数调用,接受任何类型的参数,而不仅仅是字符串字面值,所以在不运行代码就很难确定模块的依赖关系。
205 |
206 | 这就是 2015 年的 JavaScript 标准引入了自己的不同模块系统的原因。 它通常被称为 ES 模块,其中 ES 代表 ECMAScript。 依赖和接口的主要概念保持不变,但细节不同。 首先,表示法现在已整合到该语言中。 你不用调用函数来访问依赖关系,而是使用特殊的`import`关键字。
207 |
208 | ```js
209 | import ordinal from "ordinal";
210 | import {days, months} from "date-names";
211 |
212 | export function formatDate(date, format) { /* ... */ }
213 | ```
214 |
215 | 同样,`export`关键字用于导出东西。 它可以出现在函数,类或绑定定义(`let`,`const`或`var`)的前面。
216 |
217 | ES 模块的接口不是单个值,而是一组命名绑定。 前面的模块将`formatDate`绑定到一个函数。 从另一个模块导入时,导入绑定而不是值,这意味着导出模块可以随时更改绑定的值,导入它的模块将看到其新值。
218 |
219 | 当有一个名为`default`的绑定时,它将被视为模块的主要导出值。 如果你在示例中导入了一个类似于`ordinal`的模块,而没有绑定名称周围的大括号,则会获得其默认绑定。 除了默认绑定之外,这些模块仍然可以以不同名称导出其他绑定。
220 |
221 | 为了创建默认导出,可以在表达式,函数声明或类声明之前编写`export default`。
222 |
223 | ```js
224 | export default ["Winter", "Spring", "Summer", "Autumn"];
225 | ```
226 |
227 | 可以使用单词`as`重命名导入的绑定。
228 |
229 | ```js
230 | import {days as dayNames} from "date-names";
231 |
232 | console.log(dayNames.length);
233 | // → 7
234 | ```
235 |
236 | 另一个重要的区别是,ES 模块的导入发生在模块的脚本开始运行之前。 这意味着`import`声明可能不会出现在函数或块中,并且依赖项的名称只能是带引号的字符串,而不是任意的表达式。
237 |
238 | 在撰写本文时,JavaScript 社区正在采用这种模块风格。 但这是一个缓慢的过程。 在规定格式之后,花了几年的时间,浏览器和 Node.js 才开始支持它。 虽然他们现在几乎都支持它,但这种支持仍然存在问题,这些模块如何通过 NPM 分发的讨论仍在进行中。
239 |
240 | 许多项目使用 ES 模块编写,然后在发布时自动转换为其他格式。 我们正处于并行使用两个不同模块系统的过渡时期,并且能够读写任何一种之中的代码都很有用。
241 |
242 | ## 构建和打包
243 |
244 | 事实上,从技术上来说,许多 JavaScript 项目都不是用 JavaScript 编写的。有一些扩展被广泛使用,例如第 8 章中提到的类型检查方言。很久以前,在语言的某个计划性扩展添加到实际运行 JavaScript 的平台之前,人们就开始使用它了。
245 |
246 | 为此,他们编译他们的代码,将其从他们选择的 JavaScript 方言翻译成普通的旧式 JavaScript,甚至是过去的 JavaScript 版本,以便旧版浏览器可以运行它。
247 |
248 | 在网页中包含由 200 个不同文件组成的模块化程序,会产生它自己的问题。如果通过网络获取单个文件需要 50 毫秒,则加载整个程序需要 10 秒,或者如果可以同时加载多个文件,则可能需要一半。这浪费了很多时间。因为抓取一个大文件往往比抓取很多小文件要快,所以 Web 程序员已经开始使用工具,将它们发布到 Web 之前,将他们(费力分割成模块)的程序回滚成单个大文件。这些工具被称为打包器。
249 |
250 | 我们可以再深入一点。 除了文件的数量之外,文件的大小也决定了它们可以通过网络传输的速度。 因此,JavaScript 社区发明了压缩器。 通过自动删除注释和空白,重命名绑定以及用占用更少空间的等效代码替换代码段,这些工具使 JavaScript 程序变得更小。
251 |
252 | 因此,你在 NPM 包中找到的代码,或运行在网页上的代码,经历了多个转换阶段 - 从现代 JavaScript 转换为历史 JavaScript,从 ES 模块格式转换为 CommonJS,打包并压缩。 我们不会在本书中详细介绍这些工具,因为它们往往很无聊,并且变化很快。 请注意,你运行的 JavaScript 代码通常不是编写的代码。
253 |
254 | ## 模块设计
255 |
256 | 使程序结构化是编程的一个微妙的方面。 任何有价值的功能都可以用各种方式建模。
257 |
258 | 良好的程序设计是主观的 - 涉及到权衡和品味问题。 了解结构良好的设计的价值的最好方法,是阅读或处理大量程序,并注意哪些是有效的,哪些不是。 不要认为一个痛苦的混乱就是“它本来的方式”。 通过多加思考,你可以改善几乎所有事物的结构。
259 |
260 | 模块设计的一个方面是易用性。 如果你正在设计一些旨在由多人使用,或者甚至是你自己的东西,在三个月之内,当你记不住你所做的细节时,如果你的接口简单且可预测,这会有所帮助。
261 |
262 | 这可能意味着遵循现有的惯例。 `ini`包是一个很好的例子。 此模块模仿标准 JSON 对象,通过提供`parse`和`stringify`(用于编写 INI 文件)函数,就像 JSON 一样,在字符串和普通对象之间进行转换。 所以接口很小且很熟悉,在你使用过一次后,你可能会记得如何使用它。
263 |
264 | 即使没有能模仿的标准函数或广泛使用的包,你也可以通过使用简单的数据结构,并执行单一的重点事项,来保持模块的可预测性。 例如,NPM 上的许多 INI 文件解析模块,提供了直接从硬盘读取文件并解析它的功能。 这使得在浏览器中不可能使用这些模块,因为我们没有文件系统的直接访问权,并且增加了复杂性,通过组合模块与某些文件读取功能,可以更好地解决它。
265 |
266 | 这指向了模块设计的另一个有用的方面 - 一些代码可以轻易与其他代码组合。比起执行带有副作用的复杂操作的更大的模块,计算值的核心模块适用于范围更广的程序。坚持从磁盘读取文件的 INI 文件读取器, 在文件内容来自其他来源的场景中是无用的。
267 |
268 | 与之相关,有状态的对象有时甚至是有用的,但是如果某件事可以用一个函数完成,就用一个函数。 NPM 上的几个 INI 文件读取器提供了一种接口风格,需要你先创建一个对象,然后将该文件加载到对象中,最后使用特定方法来获取结果。这种类型的东西在面向对象的传统中很常见,而且很糟糕。你不能调用单个函数来完成,你必须执行仪式,在各种状态中移动对象。而且由于数据现在封装在一个特定的对象类型中,与它交互的所有代码都必须知道该类型,从而产生不必要的相互依赖关系。
269 |
270 | 通常,定义新的数据结构是不可避免的 - 只有少数非常基本的数据结构由语言标准提供,并且许多类型的数据一定比数组或映射更复杂。 但是当数组足够时,使用数组。
271 |
272 | 一个稍微复杂的数据结构的示例是第 7 章的图。JavaScript 中没有一种明显的表示图的方式。 在那一章中,我们使用了一个对象,其属性保存了字符串数组 - 可以从某个节点到达的其他节点。
273 |
274 | NPM 上有几种不同的寻路包,但他们都没有使用这种图的格式。 它们通常允许图的边带有权重,它是与其相关的成本或距离,这在我们的表示中是不可能的。
275 |
276 | 例如,存在`dijkstrajs`包。 一种著名的寻路方法,与我们的`findRoute`函数非常相似,它被称为迪科斯特拉(Dijkstra)算法,以首先编写它的艾兹格尔·迪科斯特拉(Edsger Dijkstra)命名。 `js`后缀通常会添加到包名称中,以表明它们用 JavaScript 编写。 这个`dijkstrajs`包使用类似于我们的图的格式,但是它不使用数组,而是使用对象,它的属性值是数字 - 边的权重。
277 |
278 | 所以如果我们想要使用这个包,我们必须确保我们的图以它期望的格式存储。 所有边的权重都相同,因为我们的简化模型将每条道路视为具有相同的成本(一个回合)。
279 |
280 | ```js
281 | const {find_path} = require("dijkstrajs");
282 |
283 | let graph = {};
284 | for (let node of Object.keys(roadGraph)) {
285 | let edges = graph[node] = {};
286 | for (let dest of roadGraph[node]) {
287 | edges[dest] = 1;
288 | }
289 | }
290 |
291 | console.log(find_path(graph, "Post Office", "Cabin"));
292 | // → ["Post Office", "Alice's House", "Cabin"]
293 | ```
294 |
295 | 这可能是组合的障碍 - 当各种包使用不同的数据结构来描述类似的事情时,将它们组合起来很困难。 因此,如果你想要设计可组合性,请查找其他人使用的数据结构,并在可能的情况下遵循他们的示例。
296 |
297 | ## 总结
298 |
299 | 通过将代码分离成具有清晰接口和依赖关系的块,模块是更大的程序结构。 接口是模块中可以从其他模块看到的部分,依赖关系是它使用的其他模块。
300 |
301 | 由于 JavaScript 历史上并没有提供模块系统,因此 CommonJS 系统建立在它之上。 然后在某个时候,它确实有了一个内置系统,它现在与 CommonJS 系统不兼容。
302 |
303 | 包是可以自行分发的一段代码。 NPM 是 JavaScript 包的仓库。 你可以从上面下载各种有用的(和无用的)包。
304 |
305 | ## 练习
306 |
307 | ### 模块化机器人
308 |
309 | 这些是第 7 章的项目所创建的约束:
310 |
311 | ```
312 | roads
313 | buildGraph
314 | roadGraph
315 | VillageState
316 | runRobot
317 | randomPick
318 | randomRobot
319 | mailRoute
320 | routeRobot
321 | findRoute
322 | goalOrientedRobot
323 | ```
324 |
325 | 如果你要将该项目编写为模块化程序,你会创建哪些模块? 哪个模块依赖于哪个模块,以及它们的接口是什么样的?
326 |
327 | 哪些片段可能在 NPM 上找到? 你愿意使用 NPM 包还是自己编写?
328 |
329 | ### `roads`模块
330 |
331 | 根据第 7 章中的示例编写 CommonJS 模块,该模块包含道路数组,并将表示它们的图数据结构导出为`roadGraph`。 它应该依赖于一个模块`./graph`,它导出一个函数`buildGraph`,用于构建图。 该函数接受包含两个元素的数组(道路的起点和终点)。
332 |
333 | ```js
334 | // Add dependencies and exports
335 |
336 | const roads = [
337 | "Alice's House-Bob's House", "Alice's House-Cabin",
338 | "Alice's House-Post Office", "Bob's House-Town Hall",
339 | "Daria's House-Ernie's House", "Daria's House-Town Hall",
340 | "Ernie's House-Grete's House", "Grete's House-Farm",
341 | "Grete's House-Shop", "Marketplace-Farm",
342 | "Marketplace-Post Office", "Marketplace-Shop",
343 | "Marketplace-Town Hall", "Shop-Town Hall"
344 | ];
345 | ```
346 |
347 | ### 循环依赖
348 |
349 | 循环依赖是一种情况,其中模块 A 依赖于 B,并且 B 也直接或间接依赖于 A。许多模块系统完全禁止这种情况,因为无论你选择何种顺序来加载此类模块,都无法确保每个模块的依赖关系在它运行之前加载。
350 |
351 | CommonJS 模块允许有限形式的循环依赖。 只要这些模块不会替换它们的默认`exports`对象,并且在完成加载之后才能访问对方的接口,循环依赖就没有问题。
352 |
353 | 本章前面给出的`require`函数支持这种类型的循环依赖。 你能看到它如何处理循环吗? 当一个循环中的某个模块替代其默认`exports`对象时,会出现什么问题?
354 |
--------------------------------------------------------------------------------
/13.md:
--------------------------------------------------------------------------------
1 | ## 十三、浏览器中的 JavaScript
2 |
3 | > 原文:[JavaScript and the Browser](https://eloquentjavascript.net/13_browser.html)
4 | >
5 | > 译者:[飞龙](https://github.com/wizardforcel)
6 | >
7 | > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/)
8 | >
9 | > 自豪地采用[谷歌翻译](https://translate.google.cn/)
10 | >
11 | > 部分参考了[《JavaScript 编程精解(第 2 版)》](https://book.douban.com/subject/26707144/)
12 |
13 | > Web 背后的梦想是公共信息空间,其中我们通过共享信息进行交流。 其普遍性至关重要:超文本链接可指向任何东西,无论是个人的,本地的还是全球的,无论是草稿还是高度润色的。
14 | >
15 | > Douglas Crockford,《JavaScript 编程语言》(视频讲座)
16 |
17 | 
18 |
19 | 本书接下来的章节将会介绍 Web 浏览器。可以说,没有浏览器,就没有 JavaScript。就算有,估计也不会有多少人去关心这门编程语言。
20 |
21 | Web 技术自出现伊始,其演变方式和技术上就是以分散的方式发展的。许多浏览器厂商专门为其开发新的功能,有时这些新功能被大众采纳,有时这些功能被其他功能所代替,最终形成了一套标准。
22 |
23 | 这种发展模式是把双刃剑。一方面,不会有一个集中式的组织来管理技术的演进,取而代之的是一个包含多方利益集团的松散协作架构(偶尔会出现对立)。另一方面,互联网这种无计划的发展方式所开发出来的系统,其内部很难实现一致性。事实上,它的一些部分令人疑惑,并且毫无设计。
24 |
25 | ## 网络和 Internet
26 |
27 | 计算机网络出现在 20 世纪 50 年代。如果在两台或多台计算机之间铺设电缆,那么你可以通过这些电缆互相收发数据,并实现一些神奇的功能。
28 |
29 | 如果通过连接同一个建筑中的两台机器就可以实现一些神奇的功能,那么如果可以连接全世界的机器,就可以完成更伟大的工作了。20 世纪 80 年代,人们开发了相关技术来实现这个愿景,我们将其产生的网络称为 Internet。而 Internet 的表现名副其实。
30 |
31 | 计算机可以使用这种网络向其他计算机发送位数据。为了在传输位数据的基础上,实现计算机之间的有效通信,网络两端的机器必须知道这些位所表达的实际含义。对于给定的位序列,其含义完全取决于位序列描述的信息类型与使用的编码机制。
32 |
33 | 网络协议描述了一种网络通信方式。网络协议非常多,其中包括邮件发送、邮件收取和邮件共享,甚至连病毒软件感染控制计算机都有相应的协议。
34 |
35 | 例如,HTTP(超文本传输协议,Hypertext Transfer Protocol)是用于检索命名资源(信息块,如网页或图片)的协议。 它指定发出请求的一方应该以这样的一行开始,命名资源和它正在尝试使用的协议的版本。
36 |
37 | ```
38 | GET /index.html HTTP/1.1
39 | ```
40 |
41 | 有很多规则,关于请求者在请求中包含更多信息的方式,以及另一方返回资源并打包其内容的方式。 我们将在第 18 章中更详细地观察 HTTP。
42 |
43 | 大多数协议都建立在其他协议之上。 HTTP 将网络视为一种流式设备,您可以将位放入这些设备,并使其按正确的顺序到达正确的目的地。 我们在第 11 章]中看到,确保这些事情已经是一个相当困难的问题。
44 |
45 |
46 | TCP(传输控制协议,Transmission Control Protocol)就可以帮助我们解决该问题。所有连接到互联网的设备都会使用到这种协议,而多数互联网通信都构建在这种协议之上。
47 |
48 | TCP 连接的工作方式是一台电脑必须等待或者监听,而另一台电脑则开始与之通信。一台机器为了同时监听不同类型的通信信息,会为每个监听器分配一个与之关联的数字(我们称之为端口)。大多数协议都指定了默认使用的端口。例如,当我们向使用 SMTP 协议发送一封邮件时,我们需要通过一台机器来发送邮件,而发送邮件的机器需要监听端口 25。
49 |
50 | 随后另一台机器连接到使用了正确端口号的目标机器上。如果可以连接到目标机器,而且目标机器在监听对应端口,则说明连接创建成功。负责监听的计算机名为服务器,而连接服务器的计算机名为客户端。
51 |
52 | 我们可以将该连接看成双向管道,位可以在其中流动,也就是说两端的机器都可以向连接中写入数据。当成功传输完这些位数据后,双方都可以读取另一端传来的数据。TCP 是一个非常便利的模型。我们可以说TCP就是一种网络的抽象。
53 |
54 | ## Web
55 |
56 | 万维网(World Wide Web,不要将其与 Internet 混淆)是包含一系列协议和格式的集合,允许我们通过浏览器访问网页。词组中的 Web 指的是这些页面可以轻松地链接其他网页,因此最后可以连接成一张巨大的网,用户可以在网络中浏览。
57 |
58 | 你只需将一台计算机连接到 Internet 并使用 HTTP 监听 80 端口,就可以成为 Web 的一部分。其他计算机可以通过网络,并使用 HTTP 协议获取其他计算机上的文件。
59 |
60 | 网络中的每个文件都能通过 URL(统一资源定位符,Universal Resource Locator)访问,如下所示:
61 |
62 | ```
63 | http://eloquentjavascript.net/13_browser.html
64 | | | | |
65 | protocol server path
66 | ```
67 | 该地址的第一部分告诉我们 URL 使用的是 HTTP 协议(加密的 HTTP 连接则使用`https://`来表示)。第二部分指的是获取文件的服务器地址。第三部分是我们想要获取的具体文件(或资源)的路径。
68 |
69 | 连接到互联网的机器获得一个 IP 地址,该地址是一个数字,可用于将消息发送到该机器的,类似于`"149.210.142.219"`或`"2001:4860:4860::8888"`。 但是或多或少的随机数字列表很难记住,而且输入起来很笨拙,所以你可以为一个特定的地址或一组地址注册一个域名。 我注册了`eloquentjavascript.net`,来指向我控制的机器的 IP 地址,因此可以使用该域名来提供网页。
70 |
71 | 如果你在浏览器地址栏中输入上面提到的 URL,浏览器会尝试获取并显示该 URL 对应的文档。首先,你的浏览器需要找出域名`eloquentjavascript.net`指向的地址。然后使用 HTTP 协议,连接到该地址处的服务器,并请求`/13_browser.html`这个资源。如果一切顺利,服务器会发回一个文档,然后您的浏览器将显示在屏幕上。
72 |
73 | ## HTML
74 |
75 | HTML,即超文本标记语言(Hypertext Markup Language),是在网页中得到广泛使用的文档格式。HTML 文档不仅包含文本,还包含了标签,用于说明文本结构,描述了诸如链接、段落、标题之类的元素。
76 |
77 | 一个简短的 HTML 文档如下所示:
78 |
79 | ```html
80 |
81 |
82 |
83 |
84 | My home page
85 |
86 |
87 | My home page
88 | Hello, I am Marijn and this is my home page.
89 | I also wrote a book! Read it
90 | here.
91 |
92 |
93 | ```
94 |
95 | 标签包裹在尖括号之间(`<`和`>`,小于和大于号),提供关于文档结构的信息。其他文本则是纯文本。
96 |
97 | 文档以``开头,告诉浏览器将页面解释为现代 HTML,以别于过去使用的各种方言。
98 |
99 | HTML 文档有头部(head)和主体(body)。头部包含了文档信息,而主体则包含文档自身。在本例中,头部将文档标题声明为`"My home page"`,并使用 UTF-8 编码,它是将 Unicode 文本编码为二进制的方式。文档的主体包含标题(``,表示一级标题,``到``可以产生不同等级的子标题)和两个段落(`
`)。
100 |
101 | 标签有几种形式。一个元素,比如主体、段落或链接以一个起始标签(比如`
`)开始,并以一个闭合标签(比如`
`)结束。一些起始标签,比如一个链接(``),会包含一些额外信息,其形式是`name="value"`这种键值对,我们称之为属性。在本例中,使用属性`href="http://eloquentjavascript.net"`指定链接的目标,其中`href`表示“超文本链接(Hypertext Reference)”。
102 |
103 | 某些类型的标签不会包含任何元素,这种标签不需要闭合。元数据标签``就是一个例子。
104 |
105 | > 译者注:最好还是这样闭合它们:``。
106 |
107 | 尽管 HTML 中尖括号有特殊含义,但为了在文档的文本中包含这些符号,可以引入另外一种形式的特殊标记方法。普通文本中的起始尖括号写成`<`(less than),而闭合尖括号写成`>`(greater than)。在 HTML 中,我们将一个`&`字符后跟着一个单词和分号(`;`)这种写法称为一个实体,浏览器会使用实体编码对应的字符替换它们。
108 |
109 | 与之类似的是 JavaScript 字符串中反斜杠的使用。由于 HTML 中的实体机制赋予了`&`特殊含义,因此我们需要使用`&`来表示一个`&`字符。在属性的值(包在双引号中)中使用`"`可以插入实际的引号字符。
110 |
111 | HTML 的解析过程容错性非常强。当应有的标签丢失时,浏览器会重新构建这些标签。标签的重新构建已经标准化,你可以认为所有现代浏览器的行为都是一致的。
112 |
113 | 下面的文件与之前版本显示效果相同:
114 |
115 | ```html
116 |
117 |
118 |
119 | My home page
120 |
121 | My home page
122 | Hello, I am Marijn and this is my home page.
123 |
I also wrote a book! Read it
124 | here.
125 | ```
126 |
127 | ``、`
`和``标签可以完全丢弃。浏览器知道``和``属于头部,而``属于主体。此外,我再也不用明确关闭某个段落,因为新段落开始或文档结束时,浏览器会隐式关闭段落标签。目标链接两边的引号也可以丢弃。
128 |
129 | 本书的示例通常都会省略``、``和``标签,以保持源代码简短,避免太过杂乱。但我会明确关闭所有标签并在属性两旁包含引号。
130 |
131 | 本书也会经常忽略`doctype`和`charset`声明。这并不是鼓励大家省略它们。当你忘记它们时,浏览器往往会做出荒谬的事情。 您应该认为`doctype`和`charset`元数据隐式出现在示例中,即使它们没有实际显示在文本中。
132 |
133 | ## HTML 和 JavaScript
134 |
135 | 对于本书来说,最重要的一个 HTML 标签是`
140 | ```
141 |
142 | 当浏览器在读取 HTML 时,一旦遇到`
149 | ```
150 |
151 | 这里包含的文件`code/hello.js`是和上文中相同的一段程序,`alert("hello")`。当一个页面将其他 URL 引用为自身的一部分时(比如图像文件或脚本),网页浏览器将会立即获取这些资源并将其包含在页面中。
152 |
153 | 即使`script`标签引用了一个文本文件,且并未包含任何代码,你也必须使用``来闭合标签。如果你忘记了这点,浏览器会将剩余的页面会作为脚本的一部分进行解析。
154 |
155 | 你可以在浏览器中加载ES模块(参见第 10 章),向脚本标签提供`type ="module"`属性。 这些模块可以依赖于其他模块,通过将相对于自己的 URL 用作`import`声明中的模块名称。
156 |
157 |
158 | 某些属性也可以包含 JavaScript 程序。下面展示的`"].join("");o.forEach(function(o){o.insertAdjacentHTML("beforeend",e)})}),o.mounted(function(){document.querySelector(".content").addEventListener("click",function(o){if(o.target.classList.contains("docsify-copy-code-button")){var e="BUTTON"===o.target.tagName?o.target:o.target.parentNode,t=document.createRange(),n=e.parentNode.querySelector("code"),c=window.getSelection();t.selectNode(n),c.removeAllRanges(),c.addRange(t);try{document.execCommand("copy")&&(e.classList.add("success"),setTimeout(function(){e.classList.remove("success")},1e3))}catch(o){console.error("docsify-copy-code: ".concat(o)),e.classList.add("error"),setTimeout(function(){e.classList.remove("error")},1e3)}"function"==typeof(c=window.getSelection()).removeRange?c.removeRange(t):"function"==typeof c.removeAllRanges&&c.removeAllRanges()}})})}].concat(window.$docsify.plugins||[])}();
9 | //# sourceMappingURL=docsify-copy-code.min.js.map
10 |
--------------------------------------------------------------------------------
/asset/prism-darcula.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Darcula theme
3 | *
4 | * Adapted from a theme based on:
5 | * IntelliJ Darcula Theme (https://github.com/bulenkov/Darcula)
6 | *
7 | * @author Alexandre Paradis
8 | * @version 1.0
9 | */
10 |
11 | code[class*="lang-"],
12 | pre[data-lang] {
13 | color: #a9b7c6 !important;
14 | background-color: #2b2b2b !important;
15 | font-family: Consolas, Monaco, 'Andale Mono', monospace;
16 | direction: ltr;
17 | text-align: left;
18 | white-space: pre;
19 | word-spacing: normal;
20 | word-break: normal;
21 | line-height: 1.5;
22 |
23 | -moz-tab-size: 4;
24 | -o-tab-size: 4;
25 | tab-size: 4;
26 |
27 | -webkit-hyphens: none;
28 | -moz-hyphens: none;
29 | -ms-hyphens: none;
30 | hyphens: none;
31 | }
32 |
33 | pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection,
34 | code[class*="lang-"]::-moz-selection, code[class*="lang-"] ::-moz-selection {
35 | color: inherit;
36 | background: rgba(33, 66, 131, .85);
37 | }
38 |
39 | pre[data-lang]::selection, pre[data-lang] ::selection,
40 | code[class*="lang-"]::selection, code[class*="lang-"] ::selection {
41 | color: inherit;
42 | background: rgba(33, 66, 131, .85);
43 | }
44 |
45 | /* Code blocks */
46 | pre[data-lang] {
47 | padding: 1em;
48 | margin: .5em 0;
49 | overflow: auto;
50 | }
51 |
52 | :not(pre) > code[class*="lang-"],
53 | pre[data-lang] {
54 | background: #2b2b2b;
55 | }
56 |
57 | /* Inline code */
58 | :not(pre) > code[class*="lang-"] {
59 | padding: .1em;
60 | border-radius: .3em;
61 | }
62 |
63 | .token.comment,
64 | .token.prolog,
65 | .token.cdata {
66 | color: #808080;
67 | }
68 |
69 | .token.delimiter,
70 | .token.boolean,
71 | .token.keyword,
72 | .token.selector,
73 | .token.important,
74 | .token.atrule {
75 | color: #cc7832;
76 | }
77 |
78 | .token.operator,
79 | .token.punctuation,
80 | .token.attr-name {
81 | color: #a9b7c6;
82 | }
83 |
84 | .token.tag,
85 | .token.tag .punctuation,
86 | .token.doctype,
87 | .token.builtin {
88 | color: #e8bf6a;
89 | }
90 |
91 | .token.entity,
92 | .token.number,
93 | .token.symbol {
94 | color: #6897bb;
95 | }
96 |
97 | .token.property,
98 | .token.constant,
99 | .token.variable {
100 | color: #9876aa;
101 | }
102 |
103 | .token.string,
104 | .token.char {
105 | color: #6a8759;
106 | }
107 |
108 | .token.attr-value,
109 | .token.attr-value .punctuation {
110 | color: #a5c261;
111 | }
112 |
113 | .token.attr-value .punctuation:first-child {
114 | color: #a9b7c6;
115 | }
116 |
117 | .token.url {
118 | color: #287bde;
119 | text-decoration: underline;
120 | }
121 |
122 | .token.function {
123 | color: #ffc66d;
124 | }
125 |
126 | .token.regex {
127 | background: #364135;
128 | }
129 |
130 | .token.bold {
131 | font-weight: bold;
132 | }
133 |
134 | .token.italic {
135 | font-style: italic;
136 | }
137 |
138 | .token.inserted {
139 | background: #294436;
140 | }
141 |
142 | .token.deleted {
143 | background: #484a4a;
144 | }
145 |
146 | code.lang-css .token.property,
147 | code.lang-css .token.property + .token.punctuation {
148 | color: #a9b7c6;
149 | }
150 |
151 | code.lang-css .token.id {
152 | color: #ffc66d;
153 | }
154 |
155 | code.lang-css .token.selector > .token.class,
156 | code.lang-css .token.selector > .token.attribute,
157 | code.lang-css .token.selector > .token.pseudo-class,
158 | code.lang-css .token.selector > .token.pseudo-element {
159 | color: #ffc66d;
160 | }
--------------------------------------------------------------------------------
/asset/prism-javascript.min.js:
--------------------------------------------------------------------------------
1 | Prism.languages.javascript=Prism.languages.extend("clike",{"class-name":[Prism.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])[_$A-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\.(?:prototype|constructor))/,lookbehind:!0}],keyword:[{pattern:/((?:^|})\s*)(?:catch|finally)\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|for|from|function|(?:get|set)(?=\s*[\[$\w\xA0-\uFFFF])|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],number:/\b(?:(?:0[xX](?:[\dA-Fa-f](?:_[\dA-Fa-f])?)+|0[bB](?:[01](?:_[01])?)+|0[oO](?:[0-7](?:_[0-7])?)+)n?|(?:\d(?:_\d)?)+n|NaN|Infinity)\b|(?:\b(?:\d(?:_\d)?)+\.?(?:\d(?:_\d)?)*|\B\.(?:\d(?:_\d)?)+)(?:[Ee][+-]?(?:\d(?:_\d)?)+)?/,function:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),Prism.languages.javascript["class-name"][0].pattern=/(\b(?:class|interface|extends|implements|instanceof|new)\s+)[\w.\\]+/,Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)\/(?:\[(?:[^\]\\\r\n]|\\.)*]|\\.|[^/\\\[\r\n])+\/[gimyus]{0,6}(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/,lookbehind:!0,greedy:!0},"function-variable":{pattern:/#?[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|[_$a-zA-Z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*)?\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/[_$a-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*(?=\s*=>)/i,inside:Prism.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:[_$A-Za-z\xA0-\uFFFF][$\w\xA0-\uFFFF]*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()]|\([^()]*\))+?(?=\s*\)\s*\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),Prism.languages.insertBefore("javascript","string",{"template-string":{pattern:/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}|(?!\${)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})+}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\${|}$/,alias:"punctuation"},rest:Prism.languages.javascript}},string:/[\s\S]+/}}}),Prism.languages.markup&&Prism.languages.markup.tag.addInlined("script","javascript"),Prism.languages.js=Prism.languages.javascript;
--------------------------------------------------------------------------------
/asset/search.min.js:
--------------------------------------------------------------------------------
1 | !function(){var h={},f={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function l(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function p(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function u(r,e,i,o){void 0===e&&(e="");var s,n=window.marked.lexer(e),c=window.Docsify.slugify,d={};return n.forEach(function(e){if("heading"===e.type&&e.depth<=o){var n=function(e){void 0===e&&(e="");var a={};return{str:e=e&&e.replace(/^'/,"").replace(/'$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(a[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:a}}(e.text),t=n.str,a=n.config;s=a.id?i.toURL(r,{id:c(a.id)}):i.toURL(r,{id:c(l(e.text))}),d[s]={slug:s,title:t,body:""}}else{if(!s)return;d[s]?d[s].body?(e.text=p(e),d[s].body+="\n"+(e.text||"")):(e.text=p(e),d[s].body=d[s].body?d[s].body+e.text:e.text):d[s]={slug:s,title:"",body:""}}}),c.clear(),d}function c(e){var r=[],i=[];Object.keys(h).forEach(function(n){i=i.concat(Object.keys(h[n]).map(function(e){return h[n][e]}))});var o=(e=e.trim()).split(/[\s\-,\\/]+/);1!==o.length&&(o=[].concat(e,o));function n(e){var n=i[e],s=0,c="",d=n.title&&n.title.trim(),p=n.body&&n.body.trim(),t=n.slug||"";if(d&&(o.forEach(function(e){var n,t=new RegExp(e.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&"),"gi"),a=-1;if(n=d?d.search(t):-1,a=p?p.search(t):-1,0<=n||0<=a){s+=0<=n?3:0<=a?2:0,a<0&&(a=0);var r,i=0;i=0==(r=a<11?0:a-10)?70:a+e.length+60,p&&i>p.length&&(i=p.length);var o="..."+l(p).substring(r,i).replace(t,function(e){return''+e+""})+"...";c+=o}}),0\n\n'+e.title+"
\n"+e.content+"
\n\n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=s||''+m+"
",d.hideOtherSidebarContent&&(r.classList.add("hide"),i.classList.add("hide"))}function a(e){d=e}function o(e,n){var t=n.router.parse().query.s;a(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0 7px;\n line-height: 36px;\n font-size: 14px;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n='\n \n ',t=Docsify.dom.create("div",n),a=Docsify.dom.find("aside");Docsify.dom.toggleClass(t,"search"),Docsify.dom.before(a,t)}(t),function(){var e,n=Docsify.dom.find("div.search"),t=Docsify.dom.find(n,"input"),a=Docsify.dom.find(n,".input-wrap");Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(t,"input",function(n){clearTimeout(e),e=setTimeout(function(e){return r(n.target.value.trim())},100)}),Docsify.dom.on(a,"click",function(e){"INPUT"!==e.target.tagName&&(t.value="",r())})}(),t&&setTimeout(function(e){return r(t)},500)}function s(e,n){a(e),function(e,n){var t=Docsify.dom.getNode('.search input[type="search"]');if(t)if("string"==typeof e)t.placeholder=e;else{var a=Object.keys(e).filter(function(e){return-1ul:nth-child(1) {
3 | display: none;
4 | }
5 |
6 | #main>ul:nth-child(2) {
7 | display: none;
8 | }
9 |
10 | .markdown-section h1 {
11 | margin: 3rem 0 2rem 0;
12 | }
13 |
14 | .markdown-section h2 {
15 | margin: 2rem 0 1rem;
16 | }
17 |
18 | img,
19 | pre {
20 | border-radius: 8px;
21 | }
22 |
23 | .content,
24 | .sidebar,
25 | .markdown-section,
26 | body,
27 | .search input {
28 | background-color: rgba(243, 242, 238, 1) !important;
29 | }
30 |
31 | @media (min-width:600px) {
32 | .sidebar-toggle {
33 | background-color: #f3f2ee;
34 | }
35 | }
36 |
37 | .docsify-copy-code-button {
38 | background: #f8f8f8 !important;
39 | color: #7a7a7a !important;
40 | }
41 |
42 | body {
43 | /*font-family: Microsoft YaHei, Source Sans Pro, Helvetica Neue, Arial, sans-serif !important;*/
44 | }
45 |
46 | .markdown-section>p {
47 | font-size: 16px !important;
48 | }
49 |
50 | .markdown-section pre>code {
51 | font-family: Consolas, Roboto Mono, Monaco, courier, monospace !important;
52 | font-size: .9rem !important;
53 |
54 | }
55 |
56 | /*.anchor span {
57 | color: rgb(66, 185, 131);
58 | }*/
59 |
60 | section.cover h1 {
61 | margin: 0;
62 | }
63 |
64 | body>section>div.cover-main>ul>li>a {
65 | color: #42b983;
66 | }
67 |
68 | .markdown-section img {
69 | box-shadow: 7px 9px 10px #aaa !important;
70 | }
71 |
72 |
73 | pre {
74 | background-color: #f3f2ee !important;
75 | }
76 |
77 | @media (min-width:600px) {
78 | pre code {
79 | /*box-shadow: 2px 1px 20px 2px #aaa;*/
80 | /*border-radius: 10px !important;*/
81 | padding-left: 20px !important;
82 | }
83 | }
84 |
85 | @media (max-width:600px) {
86 | pre {
87 | padding-left: 0px !important;
88 | padding-right: 0px !important;
89 | }
90 | }
91 |
92 | .markdown-section pre {
93 | padding-left: 0 !important;
94 | padding-right: 0px !important;
95 | box-shadow: 2px 1px 20px 2px #aaa;
96 | }
--------------------------------------------------------------------------------
/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/cover.jpg
--------------------------------------------------------------------------------
/img/0-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/0-0.jpg
--------------------------------------------------------------------------------
/img/1-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/1-0.jpg
--------------------------------------------------------------------------------
/img/10-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/10-0.jpg
--------------------------------------------------------------------------------
/img/11-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/img/11-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/11-2.png
--------------------------------------------------------------------------------
/img/12-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/12-0.jpg
--------------------------------------------------------------------------------
/img/12-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/13-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/13-0.jpg
--------------------------------------------------------------------------------
/img/14-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/14-0.jpg
--------------------------------------------------------------------------------
/img/14-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
24 |
--------------------------------------------------------------------------------
/img/14-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
37 |
--------------------------------------------------------------------------------
/img/14-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
26 |
--------------------------------------------------------------------------------
/img/14-4.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/img/15-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/15-0.jpg
--------------------------------------------------------------------------------
/img/16-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/16-0.jpg
--------------------------------------------------------------------------------
/img/16-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/16-1.png
--------------------------------------------------------------------------------
/img/16-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/17-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/17-0.jpg
--------------------------------------------------------------------------------
/img/17-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/17-1.png
--------------------------------------------------------------------------------
/img/17-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/img/17-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/img/17-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/17-4.png
--------------------------------------------------------------------------------
/img/17-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/17-5.png
--------------------------------------------------------------------------------
/img/18-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/18-0.jpg
--------------------------------------------------------------------------------
/img/19-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/19-0.jpg
--------------------------------------------------------------------------------
/img/19-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/19-1.png
--------------------------------------------------------------------------------
/img/19-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/19-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/2-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/2-0.jpg
--------------------------------------------------------------------------------
/img/2-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/2-1.png
--------------------------------------------------------------------------------
/img/2-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
82 |
--------------------------------------------------------------------------------
/img/2-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
156 |
--------------------------------------------------------------------------------
/img/2-4.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
176 |
--------------------------------------------------------------------------------
/img/2-5.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
148 |
--------------------------------------------------------------------------------
/img/20-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/20-0.jpg
--------------------------------------------------------------------------------
/img/21-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/21-0.jpg
--------------------------------------------------------------------------------
/img/21-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/21-1.png
--------------------------------------------------------------------------------
/img/3-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/3-0.jpg
--------------------------------------------------------------------------------
/img/4-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/4-0.jpg
--------------------------------------------------------------------------------
/img/4-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/img/4-2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/4-2.jpg
--------------------------------------------------------------------------------
/img/4-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/img/5-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/5-0.jpg
--------------------------------------------------------------------------------
/img/5-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/5-1.png
--------------------------------------------------------------------------------
/img/6-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/6-0.jpg
--------------------------------------------------------------------------------
/img/6-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/img/7-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/7-0.jpg
--------------------------------------------------------------------------------
/img/7-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/7-1.png
--------------------------------------------------------------------------------
/img/8-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/8-0.jpg
--------------------------------------------------------------------------------
/img/9-0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/9-0.jpg
--------------------------------------------------------------------------------
/img/9-1.svg:
--------------------------------------------------------------------------------
1 |
2 |
308 |
--------------------------------------------------------------------------------
/img/9-2.svg:
--------------------------------------------------------------------------------
1 |
2 |
73 |
--------------------------------------------------------------------------------
/img/9-3.svg:
--------------------------------------------------------------------------------
1 |
2 |
176 |
--------------------------------------------------------------------------------
/img/qr_alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/apachecn/eloquent-js-3e-zh/12ed9090d2ddb50e23255e1a3790e5fdb849979b/img/qr_alipay.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | now loading...
21 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/styles/ebook.css:
--------------------------------------------------------------------------------
1 | /* GitHub stylesheet for MarkdownPad (http://markdownpad.com) */
2 | /* Author: Nicolas Hery - http://nicolashery.com */
3 | /* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
4 | /* Source: https://github.com/nicolahery/markdownpad-github */
5 |
6 | /* RESET
7 | =============================================================================*/
8 |
9 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
10 | margin: 0;
11 | padding: 0;
12 | border: 0;
13 | }
14 |
15 | /* BODY
16 | =============================================================================*/
17 |
18 | body {
19 | font-family: Helvetica, arial, freesans, clean, sans-serif;
20 | font-size: 14px;
21 | line-height: 1.6;
22 | color: #333;
23 | background-color: #fff;
24 | padding: 20px;
25 | max-width: 960px;
26 | margin: 0 auto;
27 | }
28 |
29 | body>*:first-child {
30 | margin-top: 0 !important;
31 | }
32 |
33 | body>*:last-child {
34 | margin-bottom: 0 !important;
35 | }
36 |
37 | /* BLOCKS
38 | =============================================================================*/
39 |
40 | p, blockquote, ul, ol, dl, table, pre {
41 | margin: 15px 0;
42 | }
43 |
44 | /* HEADERS
45 | =============================================================================*/
46 |
47 | h1, h2, h3, h4, h5, h6 {
48 | margin: 20px 0 10px;
49 | padding: 0;
50 | font-weight: bold;
51 | -webkit-font-smoothing: antialiased;
52 | }
53 |
54 | h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
55 | font-size: inherit;
56 | }
57 |
58 | h1 {
59 | font-size: 24px;
60 | border-bottom: 1px solid #ccc;
61 | color: #000;
62 | }
63 |
64 | h2 {
65 | font-size: 18px;
66 | color: #000;
67 | }
68 |
69 | h3 {
70 | font-size: 14px;
71 | }
72 |
73 | h4 {
74 | font-size: 14px;
75 | }
76 |
77 | h5 {
78 | font-size: 14px;
79 | }
80 |
81 | h6 {
82 | color: #777;
83 | font-size: 14px;
84 | }
85 |
86 | body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
87 | margin-top: 0;
88 | padding-top: 0;
89 | }
90 |
91 | a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
92 | margin-top: 0;
93 | padding-top: 0;
94 | }
95 |
96 | h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
97 | margin-top: 10px;
98 | }
99 |
100 | /* LINKS
101 | =============================================================================*/
102 |
103 | a {
104 | color: #4183C4;
105 | text-decoration: none;
106 | }
107 |
108 | a:hover {
109 | text-decoration: underline;
110 | }
111 |
112 | /* LISTS
113 | =============================================================================*/
114 |
115 | ul, ol {
116 | padding-left: 30px;
117 | }
118 |
119 | ul li > :first-child,
120 | ol li > :first-child,
121 | ul li ul:first-of-type,
122 | ol li ol:first-of-type,
123 | ul li ol:first-of-type,
124 | ol li ul:first-of-type {
125 | margin-top: 0px;
126 | }
127 |
128 | ul ul, ul ol, ol ol, ol ul {
129 | margin-bottom: 0;
130 | }
131 |
132 | dl {
133 | padding: 0;
134 | }
135 |
136 | dl dt {
137 | font-size: 14px;
138 | font-weight: bold;
139 | font-style: italic;
140 | padding: 0;
141 | margin: 15px 0 5px;
142 | }
143 |
144 | dl dt:first-child {
145 | padding: 0;
146 | }
147 |
148 | dl dt>:first-child {
149 | margin-top: 0px;
150 | }
151 |
152 | dl dt>:last-child {
153 | margin-bottom: 0px;
154 | }
155 |
156 | dl dd {
157 | margin: 0 0 15px;
158 | padding: 0 15px;
159 | }
160 |
161 | dl dd>:first-child {
162 | margin-top: 0px;
163 | }
164 |
165 | dl dd>:last-child {
166 | margin-bottom: 0px;
167 | }
168 |
169 | /* CODE
170 | =============================================================================*/
171 |
172 | pre, code, tt {
173 | font-size: 12px;
174 | font-family: Consolas, "Liberation Mono", Courier, monospace;
175 | }
176 |
177 | code, tt {
178 | margin: 0 0px;
179 | padding: 0px 0px;
180 | white-space: nowrap;
181 | border: 1px solid #eaeaea;
182 | background-color: #f8f8f8;
183 | border-radius: 3px;
184 | }
185 |
186 | pre>code {
187 | margin: 0;
188 | padding: 0;
189 | white-space: pre;
190 | border: none;
191 | background: transparent;
192 | }
193 |
194 | pre {
195 | background-color: #f8f8f8;
196 | border: 1px solid #ccc;
197 | font-size: 13px;
198 | line-height: 19px;
199 | overflow: auto;
200 | padding: 6px 10px;
201 | border-radius: 3px;
202 | }
203 |
204 | pre code, pre tt {
205 | background-color: transparent;
206 | border: none;
207 | }
208 |
209 | kbd {
210 | -moz-border-bottom-colors: none;
211 | -moz-border-left-colors: none;
212 | -moz-border-right-colors: none;
213 | -moz-border-top-colors: none;
214 | background-color: #DDDDDD;
215 | background-image: linear-gradient(#F1F1F1, #DDDDDD);
216 | background-repeat: repeat-x;
217 | border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
218 | border-image: none;
219 | border-radius: 2px 2px 2px 2px;
220 | border-style: solid;
221 | border-width: 1px;
222 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
223 | line-height: 10px;
224 | padding: 1px 4px;
225 | }
226 |
227 | /* QUOTES
228 | =============================================================================*/
229 |
230 | blockquote {
231 | border-left: 4px solid #DDD;
232 | padding: 0 15px;
233 | color: #777;
234 | }
235 |
236 | blockquote>:first-child {
237 | margin-top: 0px;
238 | }
239 |
240 | blockquote>:last-child {
241 | margin-bottom: 0px;
242 | }
243 |
244 | /* HORIZONTAL RULES
245 | =============================================================================*/
246 |
247 | hr {
248 | clear: both;
249 | margin: 15px 0;
250 | height: 0px;
251 | overflow: hidden;
252 | border: none;
253 | background: transparent;
254 | border-bottom: 4px solid #ddd;
255 | padding: 0;
256 | }
257 |
258 | /* TABLES
259 | =============================================================================*/
260 |
261 | table th {
262 | font-weight: bold;
263 | }
264 |
265 | table th, table td {
266 | border: 1px solid #ccc;
267 | padding: 6px 13px;
268 | }
269 |
270 | table tr {
271 | border-top: 1px solid #ccc;
272 | background-color: #fff;
273 | }
274 |
275 | table tr:nth-child(2n) {
276 | background-color: #f8f8f8;
277 | }
278 |
279 | /* IMAGES
280 | =============================================================================*/
281 |
282 | img {
283 | max-width: 100%
284 | }
--------------------------------------------------------------------------------
/update.sh:
--------------------------------------------------------------------------------
1 | git add -A
2 | git commit -am "$(date "+%Y-%m-%d %H:%M:%S")"
3 | git push
--------------------------------------------------------------------------------