普通的 JS 文件没有模块作用域,没有边界,共享一个全局作用域,非常容易变量冲突,难以维护。所以引入模块,一个模块就是一个文件ES6
区别
模块化文件相比普通脚本的区别:
- 默认严格模式
- 每个模块都有自己的顶级作用域
- 如果同一个模块被多次导入,那么它的代码只会在第一次被导入时执行一次
- 模块只能通过 HTTP(s) 引入,不能从本地文件引入
- this 是 undefined
- 在浏览器中
- 使用模块化脚本需要添加 type=“module”:
<script type="module">
- 总是延时加载的,类似
defer
- 外部和内联模块脚本都可以添加
async
(比 defer 优先级高;且普通脚本只能外部引入才能添加 async) - 从另一个源加载的外部脚本需要 CORS header
- 使用模块化脚本需要添加 type=“module”:
模块脚本 | 普通脚本 | |
---|---|---|
严格模式 | 默认严格模式 | 默认非严格模式 |
作用域 | 有自己的顶级作用域 | 全局作用域 |
多次导入 | 只会在第一次被导入时执行一次 | 会执行多次 |
顶层this | undefined | window(严格和非严格都是) |
import.meta 对象包含关于当前模块的信息
导出(export)
export 可以出现在任何位置,只要在顶层作用域就行,如果处于块级作用域内,就会报错(没法做静态优化)
没有任何 import 或者 export,但是希望它被作为模块处理可以在后面加上 export {}
1. 声明时导出
2. 导出和声明分开
3. 导出别名
4. 默认导出
一个模块只能有一个默认导出,默认导出可以不要变量名称(其他文件引入时使用 default 名称),不用大括号
本质上,export default 就是输出一个叫做 default 的变量或方法
5. 重新导出
导入内容,并立即将其导出,一般用于将多个文件的导出进行汇总到 index 然后再统一导出
重新导出的模块在当前文件中不可用
导入(import)
import 必须给出相对或绝对的 URL 路径。没有任何路径的模块被称为“裸(bare)”模块,在 import 中不允许这种模块。(打包工具可以)
1. 直接导入
不会引用任何变量到当前模块,但是会执行导入的文件中的所有代码
2. 单个导入
3. 全部导入
4. 别名导入
5. 默认导入
默认导入不需要大括号,同时可以自定义名称
Tip
- import 命令具有提升效果,会提升到整个模块的头部,在编译阶段执行,在代码运行之前,由于 import 是静态执行,所以不能使用表达式和变量
- 导入对象可以改写里面的属性,并且其他模块也可以读到改写后的值。可以用于配置一个公共变量,但是这种写法很难查错
动态导入ES2020
上面的语法都是静态导入,语法简单且严格
动态按需导入模块使用 import(module)
:加载模块并返回一个 promise,该 promise 的 resolve 为一个包含其所有导出的模块对象
完整示例:
Tip
import() 函数可以用在任何地方,不仅仅是模块,非模块的脚本也可以使用
主要用途:
- 按需加载
- 条件加载
- 动态的模块路径
注意:
import()
并不是一个函数调用,只是一种特殊语法