mirror of
https://github.com/apachecn/eloquent-js-3e-zh.git
synced 2025-05-23 20:02:20 +00:00
10.
This commit is contained in:
parent
81a123867b
commit
89b1e6a5e5
76
10.md
76
10.md
@ -165,3 +165,79 @@ function require(name) {
|
|||||||
return require.cache[name].exports;
|
return require.cache[name].exports;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
在这段代码中,`readFile`是一个构造函数,它读取一个文件并将其内容作为字符串返回。标准的 JavaScript 没有提供这样的功能,但是不同的 JavaScript 环境(如浏览器和 Node.js)提供了自己的访问文件的方式。这个例子只是假设`readFile`存在。
|
||||||
|
|
||||||
|
为了避免多次加载相同的模块,`require`需要保存(缓存)已经加载的模块。被调用时,它首先检查所请求的模块是否已加载,如果没有,则加载它。这涉及到读取模块的代码,将其包装在一个函数中,然后调用它。
|
||||||
|
|
||||||
|
我们之前看到的`ordinal`包的接口不是一个对象,而是一个函数。 CommonJS 模块的特点是,尽管模块系统会为你创建一个空的接口对象(绑定到`exports`),但你可以通过覆盖`module.exports`来替换它。许多模块都这么做,以便导出单个值而不是接口对象。
|
||||||
|
|
||||||
|
通过将`require`,`exports`和`module`定义为生成的包装函数的参数(并在调用它时传递适当的值),加载器确保这些绑定在模块的作用域中可用。
|
||||||
|
|
||||||
|
提供给`require`的字符串翻译为实际的文件名或网址的方式,在不同系统有所不同。 当它以`"./"`或`"../"`开头时,它通常被解释为相对于当前模块的文件名。 所以`"./format-date"`就是在同一个目录中,名为`format-date.js`的文件。
|
||||||
|
|
||||||
|
当名称不是相对的时,Node.js 将按照该名称查找已安装的包。 在本章的示例代码中,我们将把这些名称解释为 NPM 包的引用。 我们将在第 20 章详细介绍如何安装和使用 NPM 模块。
|
||||||
|
|
||||||
|
现在,我们不用编写自己的 INI 文件解析器,而是使用 NPM 中的某个:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const {parse} = require("ini");
|
||||||
|
|
||||||
|
console.log(parse("x = 10\ny = 20"));
|
||||||
|
// → {x: "10", y: "20"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## ECMAScript 模块
|
||||||
|
|
||||||
|
CommonJS 模块很好用,并且与 NPM 一起,使 JavaScript 社区开始大规模共享代码。
|
||||||
|
|
||||||
|
但他们仍然是个简单粗暴的黑魔法。 例如,表示法有点笨拙 - 添加到`exports`的内容在局部作用域中不可用。 而且因为`require`是一个正常的函数调用,接受任何类型的参数,而不仅仅是字符串字面值,所以在不运行代码就很难确定模块的依赖关系。
|
||||||
|
|
||||||
|
这就是 2015 年的 JavaScript 标准引入了自己的不同模块系统的原因。 它通常被称为 ES 模块,其中 ES 代表 ECMAScript。 依赖和接口的主要概念保持不变,但细节不同。 首先,表示法现在已整合到该语言中。 您不用调用函数来访问依赖关系,而是使用特殊的`import`关键字。
|
||||||
|
|
||||||
|
```js
|
||||||
|
import ordinal from "ordinal";
|
||||||
|
import {days, months} from "date-names";
|
||||||
|
|
||||||
|
export function formatDate(date, format) { /* ... */ }
|
||||||
|
```
|
||||||
|
|
||||||
|
同样,`export`关键字用于导出东西。 它可以出现在函数,类或绑定定义(`let`,`const`或`var`)的前面。
|
||||||
|
|
||||||
|
ES 模块的接口不是单个值,而是一组命名绑定。 前面的模块将`formatDate`绑定到一个函数。 从另一个模块导入时,导入绑定而不是值,这意味着导出模块可以随时更改绑定的值,导入它的模块将看到其新值。
|
||||||
|
|
||||||
|
当有一个名为`default`的绑定时,它将被视为模块的主要导出值。 如果您在示例中导入了一个类似于`ordinal`的模块,而没有绑定名称周围的大括号,则会获得其默认绑定。 除了默认绑定之外,这些模块仍然可以以不同名称导出其他绑定。
|
||||||
|
|
||||||
|
为了创建默认导出,可以在表达式,函数声明或类声明之前编写`export default`。
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default ["Winter", "Spring", "Summer", "Autumn"];
|
||||||
|
```
|
||||||
|
|
||||||
|
可以使用单词`as`重命名导入的绑定。
|
||||||
|
|
||||||
|
```js
|
||||||
|
import {days as dayNames} from "date-names";
|
||||||
|
|
||||||
|
console.log(dayNames.length);
|
||||||
|
// → 7
|
||||||
|
```
|
||||||
|
|
||||||
|
另一个重要的区别是,ES 模块的导入发生在模块的脚本开始运行之前。 这意味着`import`声明可能不会出现在函数或块中,并且依赖项的名称只能是带引号的字符串,而不是任意的表达式。
|
||||||
|
|
||||||
|
在撰写本文时,JavaScript 社区正在采用这种模块风格。 但这是一个缓慢的过程。 在规定格式之后,花了几年的时间,浏览器和 Node.js 才开始支持它。 虽然他们现在几乎都支持它,但这种支持仍然存在问题,这些模块如何通过 NPM 分发的讨论仍在进行中。
|
||||||
|
|
||||||
|
许多项目使用 ES 模块编写,然后在发布时自动转换为其他格式。 我们正处于并行使用两个不同模块系统的过渡时期,并且能够读写任何一种之中的代码都很有用。
|
||||||
|
|
||||||
|
## 构建和打包
|
||||||
|
|
||||||
|
事实上,从技术上来说,许多 JavaScript 项目都不是用 JavaScript 编写的。有一些扩展被广泛使用,例如第 8 章中提到的类型检查方言。很久以前,在语言的某个计划性扩展添加到实际运行 JavaScript 的平台之前,人们就开始使用它了。
|
||||||
|
|
||||||
|
为此,他们编译他们的代码,将其从他们选择的 JavaScript 方言翻译成普通的旧式 JavaScript,甚至是过去的 JavaScript 版本,以便旧版浏览器可以运行它。
|
||||||
|
|
||||||
|
在网页中包含由 200 个不同文件组成的模块化程序,会产生它自己的问题。如果通过网络获取单个文件需要 50 毫秒,则加载整个程序需要 10 秒,或者如果可以同时加载多个文件,则可能需要一半。这浪费了很多时间。因为抓取一个大文件往往比抓取很多小文件要快,所以 Web 程序员已经开始使用工具,将它们发布到 Web 之前,将他们(费力分割成模块)的程序回滚成单个大文件。这些工具被称为打包器。
|
||||||
|
|
||||||
|
我们可以再深入一点。 除了文件的数量之外,文件的大小也决定了它们可以通过网络传输的速度。 因此,JavaScript 社区发明了压缩器。 通过自动删除注释和空白,重命名绑定以及用占用更少空间的等效代码替换代码段,这些工具使 JavaScript 程序变得更小。
|
||||||
|
|
||||||
|
因此,您在 NPM 软件包中找到的代码,或运行在网页上的代码,经历了多个转换阶段 - 从现代 JavaScript 转换为历史 JavaScript,从 ES 模块格式转换为 CommonJS,打包并压缩。 我们不会在本书中详细介绍这些工具,因为它们往往很无聊,并且变化很快。 请注意,您运行的 JavaScript 代码通常不是编写的代码。
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user