ES6 export 命令导出模块接口用法
export 命令
模块功能主要由两个命令构成:export 和 import。
export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
在 ES6 之前,JS 没有官方的模块方案,我们只能靠 IIFE 把变量藏进函数作用域,或者用 CommonJS、AMD 这类社区规范凑。ES6 把模块写进了语言层面:一个文件就是一个模块,文件内部的顶层变量默认全是私有的,外面拿不到;只有被 export 显式标出来的东西,才构成这个模块的对外接口。
这套设计的关键在于它是静态的。export 和 import 的关系在代码解析阶段就能确定,不需要执行代码。正因为如此,打包工具才有办法做 tree shaking,把没有被 import 的导出直接从产物里删掉;编辑器也才能给出准确的跳转和自动补全。而 CommonJS 的 require 是运行时才执行的函数调用,路径可以是变量拼出来的,这些静态分析就无从下手。
示例
export 有两种写法:一是直接写在声明前面(export const a = 1),二是先声明、末尾再用大括号统一列出接口。我更偏向第二种,因为把所有对外接口集中在文件底部一眼能看全,不用满文件找 export 关键字。
下面这段 HTML 通过 <script type="module"> 引入模块。注意 type="module" 是必须的,普通 <script> 里写 import 会直接报语法错误。另外模块脚本受同源策略约束,用 file:// 直接打开本地文件会被 CORS 拦掉,需要起一个本地服务才能跑通。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<script type="module">
import { test, test2s, test2 as test2ss, test2 } from './export.js';
// 触发 export.js 的 test 事件
test();
// 输出三个 这是 export.js 的 test2 变量
console.log(test2s, test2ss, test2);
</script>
</body>
</html>
被引入的 export.js 文件如下。这里演示了 as 重命名:同一个 test2 变量既以原名导出,又用 test2 as test2s 起了个别名导出。所以外部既能 import { test2 },也能 import { test2s },拿到的是同一份值——这也是为什么上面那段代码打印出三个相同的字符串。
function test() {
console.log('触发 export.js 的 test 事件');
}
const test2 = '这是 export.js 的 test2 变量';
export { test, test2, test2 as test2s };
有一点和 CommonJS 差别很大,值得单独强调:export 导出的不是值的拷贝,而是变量的绑定。如果模块内部之后又修改了这个变量,引用方读到的是修改后的新值。CommonJS 的 module.exports 则是把值拷贝出去,之后模块内怎么改都影响不到已经 require 过的一方。
反过来,引用方拿到的绑定是只读的,直接给导入的变量赋值会报错:
import { test2 } from './export.js';
test2 = 'xxx'; // TypeError: Assignment to constant variable
tip
export 命令可以出现在模块的任何位置,只要处于模块顶层就可以。 如果处于块级作用域内,就会报错。
下面这段就是典型的错误写法。export default 被塞进了函数体里,属于块级作用域,直接是语法错误——注意这个报错发生在解析阶段,整个文件一行都不会执行,不是等调用 foo() 时才抛出。
function foo() {
export default 'bar'; // SyntaxError
}
foo();
这条限制正是「静态」二字的必然结果。既然模块接口要在不执行代码的前提下就分析出来,那它就不能依赖任何运行时条件,也就不能写在 if、for、函数体这类只有跑起来才知道走不走到的位置。
如果确实需要按条件加载模块,得用动态 import()。它是一个返回 Promise 的函数形式,可以写在任意位置、路径也可以是变量拼出来的:
if (needChart) {
const { renderChart } = await import('./chart.js');
renderChart();
}
路由懒加载、大体积第三方库延后加载,靠的都是这个能力。

还没有留言,来发表第一条吧~