什么是模块
- 一个模块就是一个文件,一个脚本就是一个模块
- 模块之间可以相互加载
- export 关键字标记了可以从当前模块外部访问的变量和函数。
- import 关键字允许从其他模块导入功能。
1 | // 📁 sayHi.js |
1 | // 📁 main.html |
核心模块功能
始终使用”use strict”
模块级作用域:每个模块都有自己独立的作用域
hello.js 尝试使用在 user.js 中声明的变量 user,失败了:1
2
3
4#index.html
<script type="module" src="user.js"></script>
<script type="module" src="hello.js"></script>1
2//user.js
let user = "John";1
2//hello
alert(user); // no such variable (each module has independent variables)在浏览器中,每个
<script type="module">
也存在独立的顶级作用域1
2
3
4
5
6
7
8<script type="module">
// 变量仅在这个 module script 内可见
let user = "John";
</script>
<script type="module">
alert(user); // Error: user is not defined
</script>模块代码仅在第一次导入时被解析
如果在某个位置修改了导入的代码,那么其它的模块也可以看到就这个修改(包含源文件)
1 | // 📁 alert.js |
1 | // 在不同的文件中导入相同的模块 |
1 | <script type="module"> |
在一个模块中,”this”是 undefined
1
2
3
4
5
6
7<script>
alert(this); // window
</script>
<script type="module">
alert(this); // undefined
</script>
浏览器特定功能
- 下载外部模块脚本
<script type="module" src="...">
不会阻塞 HTML 的处理,它们会与其他资源并行加载。 - 模块脚本会等到
HTML
文档完全准备就绪(即使它们很小并且比HTML
加载速度更快),然后才会运行。 - 保持脚本的相对顺序:在文档中排在前面的脚本先执行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 第二个脚本会先于第一个脚本执行
<script type="module">
alert(typeof button); // object:脚本可以“看见”下面的 button
// 因为模块是被延迟的(deferred,所以模块脚本会在整个页面加载完成后才运行
</script>
// 相较于下面这个常规脚本:
<script>
alert(typeof button); // button 为 undefined,脚本看不到下面的元素
// 常规脚本会立即运行,常规脚本的运行是在在处理页面的其余部分之前进行的
</script>
<button id="button">Button</button>
Async 适用于内联脚本
1
2
3
4
5
6
7<!-- 所有依赖都获取完成(analytics.js)然后脚本开始运行 -->
<!-- 不会等待 HTML 文档或者其他 <script> 标签 -->
<script async type="module">
import {counter} from './analytics.js';
counter.count();
</script>外部脚本
- 具有相同 src 的外部脚本仅运行一次
1 | <!-- 脚本 my.js 被加载完成(fetched)并只被运行一次 --> |
- 从另一个源(例如另一个网站)获取的外部脚本需要 CORS header,如我们在 Fetch:跨源请求 一章中所讲的那样。换句话说,如果一个模块脚本是从另一个源获取的,则远程服务器必须提供表示允许获取的 header Access-Control-Allow-Origin
1 | <!-- another-site.com 必须提供 Access-Control-Allow-Origin --> |
不允许裸模块
在浏览器中,import 必须给出相对或绝对的 URL 路径1
2import {sayHi} from 'sayHi'; // Error,“裸”模块
// 模块必须有一个路径,例如 './sayHi.js' 或者其他任何路径兼容性
1 | <script type="module"> |