JavaScript|ES6模块化
JS中的模块其实就是多个代码的组织形式,是JS在ES6开始正式从语言级别层面支持模块的语法
一个模块就是一个文件,一个脚本就是一个模块
export
关键字标记了可以从当前模块外部访问的变量和函数。import
关键字允许从其他模块导入功能。
模块核心功能
严格模式运行
模块始终在严格模式下运行,对于一个未声明的变量进行赋值将会报错,例如:
1 |
|
模块级作用域
1 |
|
需要注意的是:在浏览器中,对于 HTML 页面,每个 <script type="module">
都存在独立的顶级作用域,下面这种就会报错
1 |
|
模块代码只在第一次导入时被解析执行
1 |
|
该admin.js模块只执行了一次。生成导出admin对象,然后这些导出在1和2的导入之间共享,因此如果更改了 admin
对象,在其他导入中也会看到。
可以简单的理解为多次导入后,导入的对象具有同一个引用
我们可以借助这种机制来实现比较经典的场景:
- 模块导出一些配置方法,例如一个配置对象。
- 在第一次导入时,我们对其进行初始化,写入其属性。可以在应用顶级脚本中进行此操作。
- 进一步地导入使用模块。
1 |
|
导出高阶用法
在声明前导出
我们可以在声明一个变量、函数、类之前进行导出
1 |
|
值得一提的是,上面声明函数之前export进行导出,本质上还是声明了一个函数,而不是一个函数表达式,因此不需要末尾打分号。只有函数表达式,末尾才需要打分号
1 |
|
具体函数表达式可以参考函数表达式
导出和声明分开
我们可以先声明,之后再导出,项目代码中比较常见
1 |
|
不要使用 import *
明确列出我们需要导入的内容,便于构建工具优化检测
为导出和导入起别名
我们也可以使用 as
让导入具有不同的名字。
例如,简洁起见,我们将 sayHi
导入到局部变量 hi
,将 sayBye
导入到 bye
:
1 |
|
导出也具有类似的语法。
我们将函数导出为 hi
和 bye
:
1 |
|
现在 hi
和 bye
是在外面使用时的正式名称:
1 |
|
export default
为了专注一个模块只做一件事,js提供了export default
的语法
每个文件应该只有一个 export default
1 |
|
1 |
|
命名的导出 | 默认的导出 |
---|---|
export class User {...} |
export default class User {...} |
import {User} from ... |
import User from ... |
一般情况下,我们约定一个模块要么是命名的导出,要么就是默认的导出,一般不会进行混用
重新导出
在包的源码中比较常见,主要的目的是为了将源码中所有的导出内容,统一在index.js
中进行声明供外部引用
语法结构是 export ... from ...
1 |
|
等价于
1 |
|
(我们假设foo在foo.js中是默认的导出,即export default foo
)
默认导出特殊处理
上面也看到了,对于默认的导出需要一个 default as foo
的处理,
假设我们现在有一个脚本默认导出了一个对象
1 |
|
在新的文件中:export User from './user.js'
是语法错误
我们必须明确写出 export {default as User}
正如上面的处理那样
因此可以看到,在重新导出时,默认导出需要特殊处理,因此很多开发者也不喜欢默认导出,统一使用命名导出的方式