前言
JavaScript 用“共享一切”的方法加载代码,这是该语言中最容易出错且容易令人感到困惑的地方。随着 Web 应用变得更加复杂,JavaScript 代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。ES6 的一个目标是解决作用域问题,也为了使 JS 应用程序显得有序,于是引进了模块。
1. 什么是模块
模块是自动运行在严格模式下并且没有办法退出运行的JavaScript代码。
模块真正的魔力所在是仅导出和导入你需要绑定,而不是将所有东西都放到一个文件。只有很好地理解了导出和导入才能理解模块和脚本的区别。
2. 导出的基本语法
// 导出数据 export var color = "red"; // 导出函数 export function sum(a, b) { return a + b; } // 导出类 // 。。。 复制代码
任何未显示导出的变量、函数或类都是模块私有的,无法从模块外部访问。
3. 导入的基本语法
从模块中导出的功能可以通过 import 关键字在另一个模板中访问。
import { identifier1, identifier2 } from "./example.js"; 复制代码
导入绑定的列表看起来与解构对象很相似,但不是。
导入单个绑定
不能给导入的绑定重新赋值
// 只导入一个 import { sum } from "./example.js"; console.log(sum(1, 2)); sum = 1; // 抛出一个错误 复制代码
为了更好地兼容多个浏览器和 Node.js 环境,一定要在字符串之前包含/、,/或../来表示要导入的文件。
导入多个绑定
import { sum1, sum2 } from "./example.js"; 复制代码
导入整个模块
// 导入一切 import * as example from "./example.js"; 复制代码
这种导入格式被称为命名空间导入(namespace import)
模块语法的限制
export语句不允许出现在if语句中,不能有条件导出或以任何方式动态导出。模块语法存在的一个原因是要让JavaScript引擎静态地确定哪些可以导出。
4. 导出和导入时重命名
导出重命名
function sum(a, b) { return a + b; } export { sum as add }; 复制代码
导入重命名
import { add as sum } from "./example.js"; 复制代码
5. 模块的默认值
导出默认值
export default function (a, b) { return a + b; } 复制代码
function sum(a, b) { return a + b; } export default sum; 复制代码
导入默认值
不使用大括号,这种语法是最纯净的。
import sum from "./example.js"; 复制代码
6. 重新导出一个绑定
import { sum } from "./example.js"; export { sum }; 复制代码
你还可以这样写:
export { sum as add } from "./example.js"; 复制代码
7. 无绑定导入
内建对象的共享定义可以在模块中访问,对这些对象所做的更改将反应在其他模块中
例如,要向所有数组添加 pushAll()方法。
Array.prototype.pushAll = function (items) { if (!Array.isArray(items)) { throw new TypeError("参数必须是一个数组。"); } return this.push(...items); }; 复制代码
无绑定导入最有可能被应用于创建 Polyfill 和 Shim。
8.加载模块
ES6 并没有尝试为所有 JavaScript 环境一套统一的标准,它只规定了语法,并将加载机制抽象到一个未定义的内部方法 HostResolveImportModule 中。
在 Web 浏览器中使用模块
<script type="module" src="module.js"></script> <script type="module"> import { sum } from "./example.js"; let result = sum(1, 2); </script> 复制代码
Web 浏览器中模块加载顺序
<script>元素按照它们被引入的顺序加载。
Web 浏览器中异步模块加载
async 属性应用于脚本时,脚本文件将在文件完全下载并解析后执行。脚本在下载完成后立即执行,而不必等待包含的文档完成解析。
<!-- 无法保证这两个哪个先执行 --> <script type="module" async src="module1.js"></script> <script type="module" async src="module2.js"></script> 复制代码
两个文件都被异步加载,只是简单地看这个代码判断不出哪个模块先执行,原则是谁先加载完谁先执行。
将模块作为 Worker 加载
let worker = new Worker("module.js", { type: "module" }); 复制代码
9. 浏览器模块说明符解析
浏览器说明符要求模块说明符具有以下几种格式之一:
- 以/开头的解析为从根目录开始
- 以./开头的解析为从当前目录开始
- 以../开头的解析为从父目录开始
- URL 格式
最后
⚽本文介绍了ES6中的模块,模块其实就是一种打包和封装功能的方式~