在早期,JavaScript 一般是用来当做独立执行的脚本,它们的程序比较小,随着 JavaScript 的发展,JavaScript 的程序也更加的复杂,所以就需要将程序按模块划分,并且模块之间可以互相导入,由此催生了很多的规范,如 CMD 与 AMD,现如今 ES6 也提供原生的模块机制支持。
模块真正的魔力所在是仅导出和导入你需要的绑定,而不是将所用东西都放到一个文件。只有很好地理解了导出和导入才能理解模块与脚本的区别。
模块的导出
通过 export 关键字可以将一个值、函数、对象导出,如
export const a = 1; |
模块不支持动态的导出,不能在函数或者 if 语句块内导出
if (condition) { |
我们导出变量时,可以通过 as 为变量重命名,例如
function add() {} |
模块的导入
通过 import 语法可以在其他模块导出的内容进行导入,例如 a.js 导出如下
// a.js |
我们在 b.js 中使用 import 语句进行导入
// b.js |
需要注意的是,import 导入为只读导入,即不能修改导入的值
import {name} from "./a.js"; |
但是考虑下面的情况
// a.js |
// b.js |
可以通过 setName 来修改 name 的值。 同样,我们也可以通过 as 语法为导入的变量重命名
// b.js |
通过 **import *** 可以导入模块中的所有内容
import * as a from './a.js' |
模块的默认值
我们可以通过 export default 导出模块的默认值
// a.js |
通过 export default 导出的变量可以直接通过 import 引用
// b.js |
默认导出还可以写为
export add as default |
这种写法同 export default 的效果一致,另外可以通下面的这种方式为默认导入重命名
// 为默认导入重命名 |
当同时导入默认导出与其他导出时,可以这么写
// a.js |
// b.js |
浏览器中使用模块
在 script 中使用模块
要在 script 标签中使用模块,需要设置 script 标签的 type=”module”
<script type="module"> |
模块加载顺序
如果 script 的 type 属性被设置为了 module,那么会自动为每一个 script 标签添加一个 defer 属性,当解析到此 script 标签时,它会立即下载该模块文件,但是下载完成后不会执行,只有等到文档解析完毕才会执行。
并且执行的顺序与 script 定义的顺序有关,定义在前的 script 标签先执行
<script type="module" src="./module1.js"></script> |
虽然可能 module2.js 先下载完毕,但是 module1.js 定义在签名,所以 module1.js 会先于 module2.js 执行。
一个模块会被多个模块所引用,但是所有的模块只会被执行一次,如果有多个模块导入同一模块,第一次导入时,执行该模块,然后放入缓存,第二个及以后导入该模块时直接从缓存中获得导入的模块,而不会再次执行此模块。
浏览器中的模块说明符
当我们使用 import 导入模块时,浏览器要求路径是以下几种格式:
- . /:从当前目录开始解析
- ../:从父目录开始解析
- /:从根目录开始解析
所以下面的导入语句在浏览器中是无效的
import add from 'example.js' |
因为上述的导入路径不是以 ./
../
或者 /
开头,所以无法被浏览器加载。