学习ES6模块

在 ES6 之前,一个应用的每个 JS 文件所定义的所有内容都由全局作用域共享。当 web 应用变得更加复杂、需要使用越来越多的 JS代码时,这种方式导致了诸多问题,例如命名冲突、安全问题等。 ES6 的设计目标之一就是要解决作用域问题,并让 JS 应用变得更有条理。这便是模块的切入点。

介绍

  1. 模块代码自动运行在严格模式下,并且没有任何办法跳出严格模式;
  2. 在模块的顶级作用域创建的变量,不会被自动添加到共享的全局作用域,它们只会在模块顶级作用域的内部存在;
  3. 模块顶级作用域的 this 值为 undefined
  4. 对于需要让模块外部代码访问的内容,模块必须导出它们;
  5. 允许模块从其他模块导入绑定。

基本导出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// common.js
// 导出数据
export const color = 'red';
// 导出函数
export function sum(num1, num2) {
return num1 + num2;
}
function sort() {
// ....
}
// 稍后导出
export {sort};

基本导入

1
2
3
4
5
6
7
8
9
// 分别导出多个
import {sum, sort} from './common.js';
// 使用
sum();
// 完全导入一个模块
import * as common from './common.js';
// 使用
common.sum();

重命名导出与导入

1
2
3
4
5
6
7
8
// common.js
function sum (num1, num2) {
return num1 + num2;
}
export {sum as add};
// index.js
import {add as sum} from './common.js';

导出默认值

1
2
3
4
// common.js
export default function hello() {
return 'hello world';
}

导入默认值

1
2
// index.js
import hello from './common.js';

绑定的再导出

1
2
3
4
5
6
7
8
9
10
11
import { sum } from './common.js';
export { sum }
// 简写
export { sum } from './common.js';
// 改名后导出
export { sum as add } from './common.js';
// 全部导出
export * from './common.js';

无绑定的导入

1
2
// 适用于没有任何导出,只是修改全局作用域的对象
import './common.js';

模块在浏览器中的加载顺序

1
2
3
4
5
6
7
8
9
10
11
<!-- this will execute first -->
<script type="module" src="module1.js"></script>
<!-- this will execute second -->
<script type="module">
import { sum } from "./example.js";
let result = sum(1, 2);
</script>
<!-- this will execute third -->
<script type="module" src="module2.js"></script>

所有模块,无论是用 <script type="module"> 显式包含的,还是用 import 隠式包含的,都会依照次序加载与执行。在前面的范例中,完整的加载次序是:

  1. 下载并解析 module1.js
  2. 递归下载并解析在 module1.js 中使用 import 导入的资源;
  3. 解析内联模块;
  4. 递归下载并解析在内联模块中使用 import 导入的资源;
  5. 下载并解析 module2.js
  6. 递归下载并解析在 module2.js 中使用 import 导入的资源。

一旦加载完毕,直到页面文档被完整解析之前,都不会有任何代码被执行。在文档解析完毕r后,会发生下列行为:

  1. 递归执行 module1.js 导入的资源;
  2. 执行 module1.js
  3. 递归执行内联模块导入的资源;
  4. 执行内联模块;
  5. 递归执行 module2.js 导入的资源;
  6. 执行 module2.js