模块
模块是相对于普通 js 文件而言以不同方式加载的 js 文件。特点有:
- 代码自动在严格模式下运行。
- 顶级作用域中的变量不会自动添加到共享的全局作用域中,顶级作用域中的 this 值为 undefined。
- 代码中不允许使用 HTML 风格的注释。
- 外部代码想要使用模块中的内容时,该内容必须从模块中导出。
- 模块可以从其他模块中导入绑定。
基本的导出
模块中声明的变量、函数或者类,在声明语句最前面加上 'export' 表示将该变量、函数或者类导出。这种方式导出的函数或者类必须具有名称,不能导出匿名类或者匿名函数。可以使用 'export { }' 方式导出引用。
基本的导入
从某模块中导入一个或多个 export 导出的内容的语法为
import {var1, ref1} from './some.js';
大括号中的标识符与被导入模块中定义的标识符对应,本质上导入的标识符是对应模块中标识符对应的值(或引用)的只读绑定,不允许修改值。如果需要导入一个模块中所有可导入的内容时,使用命名空间导入,这种导入方式会将模块作为一个对象,然后将所有的可导入内容作为这个对象的属性。语法为
import * as obj from './some.js';
对同一个模块使用多次导入语句的前提下,在第一次执行导入语句时,该模块被实例化保留在内存中,之后对该模块的导入都是使用这个内存中的实例化模块。
export 和 import 只能在顶级作用域中使用。
由于导出的标识符都是只读绑定,不能直接修改其值。但是如果导入的函数行为修改了某变量值,调用这个函数时,函数会回到最开始的模块中执行,修改模块中对应变量的值。如果这个变量被导入了,那么这个变量的值会发生变化。
重命名导入导出
在导入导出时,可以为导入导出的标识符名称起别名,这个别名表示原始的标识符,以后使用时只能使用别名。
// 导入
import {origin as alias} from './some.js';
// 导出
export {origin as alias};
模块默认值
模块的默认值是使用 default 指定的单个变量、函数或者类。一个模块中只能指定一个默认值。
默认值的导出方式有
// 1
export default ref() {}
// 2
ref() {}
export default ref;
// 3
ref() {}
export {ref as default};
只导入默认值时,有
// name 名称自定义,表示默认的导出值
import name from './some.js';
如果默认值和非默认值都需要导入,则默认值的导入必须位于前面。
import name, {ref} from './some.js';
// 等价于
import {default as name, ref} from './some.js'
绑定的再导出
如果当前模块从另一个模块中导入了一些值,然后想将这些值从当前模块中导出,语法为
// {} 中放入想要导出的标识符,可以起别名,也可以不用 {} 直接用 * 导出所有可导出内容
export {} from './some.js'
无绑定的导入
如果一个模块中没有任何导入导出语句,那么导入该模块时,表示将该模块的语句执行了一遍。模块中的语句可能对内置对象属性有修改。这种导入方式为
import './some.js';
加载模块
在 script 标签中使用模块。
<script type="module" src="some.js"></script>
<script type="module">
import name from "./some.js";
</script>
浏览器在加载页面时,遇到有 type='module' 的 script 的标签时,若该标签有 src 属性,则下载对应的 js 文件,如果文件中有 import 语句,则递归解析并下载 import 语句中的文件;如果该标签没有 src 语句(内联的 script ),此时若有 import 语句,则递归解析并下载 import 语句中的文件。按照上述流程在整个文档上以从上到下的顺序解析完所有的 script 标签。当页面加载完成之后,按照上述流程顺序执行 js 代码。
若有 type='module' 且有 src 的 script 标签具有 async 属性,则表明在下载并解析导入的 js 文件中,import 语句导入的文件(若有 import 语句)之后,立即执行该 js 文件,不等待文档加载完成再执行。因此有多个 script 标签有 aysnc 属性时,无法知道具体哪个 js 文件的代码先执行。
import 语句中 from 后面的文件路径必须以 '/'、'./'、'../' 或者 url 作为路径开头。
参考
[1] Zakas, Understanding ECMAScript 6, 2017.