「这是我参与2022首次更文挑战的第1天,活动详情查看:2022首次更文挑战」。
前言
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中的模块,模块其实就是一种打包和封装功能的方式~
🏀该篇博客对应的md文档已更新在Github仓库,欢迎Star~
🏉此外笔者还有其他专栏,欢迎阅读~
🏐玩转CSS之美
🎱Vue从放弃到入门
🎳深入浅出JavaScript