js 基础 (ES 模块)

ES 模块语法

1、模块化的背景

JavaScript 程序本来很小——在早期,它们大多被用来执行独立的脚本任务,在你的 web 页面需要的地方提供一定交互,所以一般不需要多大的脚本。过了几年,我们现在有了运行大量 JavaScript 脚本的复杂程序,还有一些被用在其他环境(例如 Node.js)

因此,近年来,有必要开始考虑提供一种将 JavaScript 程序拆分为可按需导入的单独模块的机制Node.js 已经提供这个能力很长时间了,还有很多的 JavaScript 库和框架已经开始了模块的使用(例如,CommonJS 和基于 AMD 的其他模块系统 如 RequireJS,以及最新的 Webpack 和 Babel)。

好消息是,最新的浏览器开始原生支持模块功能了,这是本文要重点讲述的。这会是一个好事情 —- 浏览器能够最优化加载模块,使它比使用库更有效率:使用库通常需要做额外的客户端处理。

2、介绍一个例子

为了演示模块的使用,我们创建了一系列简单的示例 ,你可以在 GitHub 上找到。这个例子演示了一个简单的模块的集合用来在 web 页面上创建了一个 标签,在 canvas 上绘制 (并记录有关的信息) 不同形状。

备注: 如果你想去下载这个例子在本地运行,你需要通过本地 web 服务器去运行。

3、基本的示例文件的结构

在我们的第一个例子(参见 basic-modules)文件结构如下:

index.html
main.js
modules/
    canvas.js
    square.js

备注: 在这个指南的全部示例项目的文件结构是基本相同的;需要熟悉上面的内容

modules 目录下的两个模块的描述如下:

  • canvas.js — 包含与设置画布相关的功能:
    • create() — 在指定 ID 的包装器
      内创建指定 widthheight 的画布,该 ID 本身附加在指定的父元素内。返回包含画布的 2D 上下文和包装器 ID 的对象。
    • createReportList()— 创建一个附加在指定包装器元素内的无序列表,该列表可用于将报告数据输出到。返回列表的 ID。
  • square.js — 包含:
    • name — 包含字符串 ‘square’ 的常量。
    • draw() — 在指定画布上绘制一个正方形,具有指定的大小,位置和颜色。返回包含正方形大小,位置和颜色的对象。
    • reportArea() — 在给定长度的情况下,将正方形区域写入特定报告列表。
    • reportPerimeter() — 在给定长度的情况下,将正方形的周长写入特定的报告列表。

备注: 在原生 JavaScript 模块中,扩展名 .mjs 非常重要,因为使用 MIME-typejavascript/esm 来导入文件(其他的 JavaScript 兼容 MIME-type application/javascript 也可以),它避免了严格的 MIME 类型检查错误,像 “The server responded with a non-JavaScript MIME type”。除此之外,.mjs 的扩展名很明了(比如这个就是一个模块,而不是一个传统 JavaScript 文件),还能够和其他工具互相适用。看这个 Google’s note for further details。

4、.mjs.js

纵观此文,我们使用 .js 扩展名的模块文件,但在其他一些文章中,你可能会看到.mjs扩展名的使用。V8 推荐了这样的做法,比如有下列理由:

  • 比较清晰,这可以指出哪些文件是模块,哪些是常规的 JavaScript。
  • 这能保证你的模块可以被运行时环境和构建工具识别,比如 Node.js 和 Babel。

但是我们决定继续使用 .js 扩展名,未来可能会更改。为了使模块可以在浏览器中正常地工作,你需要确保你的服务器能够正常地处理 Content-Type 头,其应该包含 JavaScript 的 MIME 类型 text/javascript。如果没有这么做,你可能会得到 一个严格 MIME 类型检查错误:“The server responded with a non-JavaScript MIME type(服务器返回了非 JavaScript MIME 类型)”,并且浏览器会拒绝执行相应的 JavaScript 代码。多数服务器可以正确地处理 .js 文件的类型,但是 .mjs 还不行已经可以正常响应 .mjs 的服务器有 GitHub 页面 和 Node.js 的 http-server。

如果你已经在使用相应的环境了,那么一切正常。或者如果你还没有,但你知道你在做什么(比如你可以配置服务器以为 .mjs 设置正确的 Content-Type)。但如果你不能控制提供服务,或者用于公开文件发布的服务器,这可能会导致混乱。

为了学习和保证代码的可移植的目的,我们建议使用 .js

如果你认为使用 .mjs 仅用于模块带来的清晰性非常重要,但不想引入上面描述的相应问题,你可以仅在开发过程中使用 .mjs,而在构建过程中将其转换为 .js

另注意:

  • 一些工具不支持 .mjs,比如 TypeScript。
  • 注意:模块和它们的依赖可以通过在元素中用rel="modulepreloaded"指定它们来预加载。这可以显著减少使用模块时的加载时间。

    9、其他模块与标准脚本的不同

    • 你需要注意本地测试——如果你通过本地加载 HTML 文件(比如一个 file:// 路径的文件),你将会遇到 CORS 错误,因为 JavaScript 模块安全性需要。你需要通过一个服务器来测试
    • 另请注意,你可能会从模块内部定义的脚本部分获得与标准脚本中不同的行为。这是因为模块自动使用严格模式
    • 加载一个模块脚本时不需要使用 defer 属性 (see

你可能感兴趣的:(前端,javascript,开发语言,ecmascript)