【ES6】module基本用法
1.概述
在ES6之前,社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种。前者用于服务器,后者用于浏览器。【只能在运行时确定】ES6 module是在浏览器和服务器上的通用解决方案。
CommonJS
模块就是对象,输入时必须查找对象属性。
// CommonJS模块
let { stat, exists, readfile } = require('fs');
// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
上面代码的实质是整体加载fs
模块(即加载fs
的所有方法),生成一个对象(_fs
),然后再从这个对象上面读取 3 个方法。
这种加载称为“运行时加载”,因为只有运行时才能得到这个对象,导致完全没办法在编译时做“静态优化”。
ES6 module
是通过export
命令显式指定输出的代码,再通过import
命令输入。
设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。
// ES6模块
import { stat, exists, readFile } from 'fs';
上面代码的实质是从fs
模块加载 3 个方法,其他方法不加载。
这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载,效率要比 CommonJS 模块的加载方式高。当然,这也导致了没法引用 ES6 模块本身,因为它不是对象。
模块功能主要由两个命令构成:export
和import
。
export
命令用于规定模块的对外接口;import
命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量。
2.模块加载
所有的模块都会像<script defer>
①【延迟推迟执行脚本】加载的脚本一样按顺序执行。
也可以给模块标签添加
async
属性【异步②】,这样模块的执行顺序不再与<script>
标签顺序绑定,也不会等待文档完成解析才执行。但是入口模块仍需等待其依赖加载完成。
模块标签代码分为两种类型:
- 嵌入模块代码:
<script type="module"></scrip>
(只适合做入口模块) - 外部加载JS模块:
<script type="module" src="module.js"></scrip>
一个页面上的入口模块没有数量限制,也可以重复,但实际上一个模块只会在一个页面被加载一次。
浏览器支持:
- ES6模块既可以通过浏览器原生加载,也可以与第三方加载器和构建工具一起加载。
- 完全支持ES6模块的浏览器可以从顶级模块加载整个依赖图,异步递归地按需加载。
模块行为:
- 只在加载后执行
- 只能加载一次
- 单例
- 可以定义公共接口,其他模块可以基于这个公共接口观察和交互
- 可以请求加载其他模块
- 支持循环依赖
新行为:
- 默认在严格模式下执行
- 不共享全局命名空间
- 模块顶级
this
为undefined
(一般是window
) var
声明不会添加到window
对象- 异步加载
[①] 解析到标签后立即下载模块文件,但执行会延迟到文档解析完成。
[②] 解析到标签后进行异步下载,下载成功后立马执行。
3.模块导出export
导出语句必须在模块顶级,不能嵌套再某个语句块(如条件语句if)中。
一般来说,声明、赋值和导出标识符最好分开,同时也让export语句集中在一块。
错误形式:
- 行内默认导出不能出现变量声明
- 只有标识符可以出现在export子句,不能是123这种数值
- 别名只能出现在export子句中
命名导出 name export
出现次数没有限制,顺序也没有限制(但是尽量先声明后导出)
export const foo = "foo"
const foo = "foo"
const bar = "bar"
export {foo}
export {foo as MyFoo} // 别名
export {foo as default} // 别名为default则为默认导出
export {foo. bar as MyBar} // 可以同时部分或全部导出,可以分别命名别名
默认导出 default export
default
关键字将一个值声明为默认导出,每个模块只能有一个默认导出。
默认导出和命名导出不冲突,可以组合为一行export { foo as default, bar}
4.模块导入import
导入语句必须在模块顶级,不能嵌套再某个语句块(如条件语句if)中。
import语句会被提升到模块顶部,所以语句顺序不重要,但是推荐放在模块顶部。
模块标识符可以是相对路径、绝对路径【必须是纯字符串,不能是计算结果】
在浏览器中通过标识符原生加载模块,则文件必须带有 .js扩展名。
导入对模块而言是只读的。(不能直接修改导出值,但是可以修改对象的属性)
可以同时使用以下两种导出方式来获取
命名导出
可以使用*
批量获取并命名别名import * as Foo from '../xxx/xx'
也可以花括号{}
指名导入import {foo, bar} from './foo.js'
默认导出
就好像整个模块就是导出的值一样
- 可以不使用花括号
{}
- 可以使用
default
关键字并提供别名导入import { default as foo } from './foo.js'
参考资料
es6.ruanyifeng.com/#docs/modul…
JavaScript高级程序设计(第4版)第26章 模块
转载自:https://juejin.cn/post/7139483132423569416